mirror of
https://github.com/libretro/Mu.git
synced 2026-02-14 05:35:20 +00:00
Compare commits
12 Commits
serial
...
tungstenT3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b39468a32 | ||
|
|
c33be1988d | ||
|
|
82aa0c6fc0 | ||
|
|
018ed97874 | ||
|
|
be43d3a39a | ||
|
|
ee822d2800 | ||
|
|
46918f8d0f | ||
|
|
5601f0c3d4 | ||
|
|
349ff5d92f | ||
|
|
be02f9b313 | ||
|
|
87f5312954 | ||
|
|
34426a791b |
15
.circleci/config.yml
Normal file
15
.circleci/config.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
# Use the latest 2.1 version of CircleCI pipeline processing engine, see https://circleci.com/docs/2.0/configuration-reference/
|
||||
version: 2.1
|
||||
|
||||
# Use a package of configuration called an orb, see https://circleci.com/docs/2.0/orb-intro/
|
||||
orbs:
|
||||
# Declare a dependency on the welcome-orb
|
||||
welcome: circleci/welcome-orb@0.3.1
|
||||
|
||||
# Orchestrate or schedule a set of jobs, see https://circleci.com/docs/2.0/workflows/
|
||||
workflows:
|
||||
# Name the workflow "Welcome"
|
||||
Welcome:
|
||||
# Run the welcome/run job in its own container
|
||||
jobs:
|
||||
- welcome/run
|
||||
22
.gitignore
vendored
22
.gitignore
vendored
@@ -17,24 +17,4 @@
|
||||
/tools/palm/hwTestSuite/TstSuite-sections.ld
|
||||
/tools/desktop/build-BufferGraphViewer-*
|
||||
/tools/desktop/build-MakePalmBitmap-*
|
||||
/tools/desktop/export16BitImageProperly/convert
|
||||
|
||||
# CLion
|
||||
.idea/workspace.xml
|
||||
.idea/discord.xml
|
||||
|
||||
# CMake
|
||||
cmake-build-debug/
|
||||
cmake-build-release/
|
||||
cmake-build-debug-mingw/
|
||||
cmake-build-release-mingw/
|
||||
cmake-build-debug-visual-studio/
|
||||
cmake-build-release-visual-studio/
|
||||
cmake-build-debug-visual-studio-1/
|
||||
cmake-build-release-visual-studio-1/
|
||||
|
||||
# Test ROM
|
||||
userdata-palmos41-en-m515.ram
|
||||
userdata-en-m515.ram
|
||||
palmos41-en-m515.rom
|
||||
default-palmos41-en-m515.ram
|
||||
/tools/desktop/export16BitImageProperly/convert
|
||||
259
.gitlab-ci.yml
259
.gitlab-ci.yml
@@ -1,259 +0,0 @@
|
||||
##############################################################################
|
||||
################################# BOILERPLATE ################################
|
||||
##############################################################################
|
||||
|
||||
# Core definitions
|
||||
.core-defs:
|
||||
variables:
|
||||
CORENAME: mu
|
||||
JNI_PATH: libretroBuildSystem
|
||||
MAKEFILE_PATH: libretroBuildSystem
|
||||
MAKEFILE: Makefile.libretro
|
||||
|
||||
# Inclusion templates, required for the build to work
|
||||
include:
|
||||
################################## DESKTOPS ################################
|
||||
# Windows 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-x64-mingw.yml'
|
||||
|
||||
# Windows 32-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-i686-mingw.yml'
|
||||
|
||||
# Windows msvc10 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-x64-msvc10-msys2.yml'
|
||||
|
||||
# Windows msvc10 32-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-i686-msvc10-msys2.yml'
|
||||
|
||||
# Windows msvc05 32-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-i686-msvc05-msys2.yml'
|
||||
|
||||
# Linux 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-x64.yml'
|
||||
|
||||
# MacOS 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/osx-x64.yml'
|
||||
|
||||
# MacOS ARM 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/osx-arm64.yml'
|
||||
|
||||
################################## CELLULAR ################################
|
||||
# Android
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/android-jni.yml'
|
||||
|
||||
# iOS 9
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ios9.yml'
|
||||
|
||||
# iOS
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ios-arm64.yml'
|
||||
|
||||
# tvOS
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/tvos-arm64.yml'
|
||||
|
||||
################################## CONSOLES ################################
|
||||
# Dingux (GCW Zero)
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/dingux-mips32.yml'
|
||||
|
||||
# Nintendo 3DS
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ctr-static.yml'
|
||||
|
||||
# Nintendo GameCube
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ngc-static.yml'
|
||||
|
||||
# Nintendo Wii
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/wii-static.yml'
|
||||
|
||||
# Nintendo WiiU
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/wiiu-static.yml'
|
||||
|
||||
# Nintendo Switch
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/libnx-static.yml'
|
||||
|
||||
# PLayStation 2
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ps2-static.yml'
|
||||
|
||||
# PlayStation Vita
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/vita-static.yml'
|
||||
|
||||
#################################### MISC ##################################
|
||||
# Emscripten
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/emscripten-static.yml'
|
||||
|
||||
# Stages for building
|
||||
stages:
|
||||
- build-prepare
|
||||
- build-shared
|
||||
- build-static
|
||||
|
||||
##############################################################################
|
||||
#################################### STAGES ##################################
|
||||
##############################################################################
|
||||
|
||||
################################### DESKTOPS #################################
|
||||
# Windows 64-bit
|
||||
libretro-build-windows-x64:
|
||||
extends:
|
||||
- .libretro-windows-x64-mingw-make-default
|
||||
- .core-defs
|
||||
|
||||
# Windows 32-bit
|
||||
libretro-build-windows-i686:
|
||||
extends:
|
||||
- .libretro-windows-i686-mingw-make-default
|
||||
- .core-defs
|
||||
|
||||
# Windows msvc10 64-bit
|
||||
libretro-build-windows-msvc10-x64:
|
||||
extends:
|
||||
- .libretro-windows-x64-msvc10-msys2-make-default
|
||||
- .core-defs
|
||||
|
||||
# Windows msvc10 32-bit
|
||||
libretro-build-windows-msvc10-i686:
|
||||
extends:
|
||||
- .libretro-windows-i686-msvc10-msys2-make-default
|
||||
- .core-defs
|
||||
|
||||
# Windows msvc05 32-bit
|
||||
libretro-build-windows-msvc05-i686:
|
||||
extends:
|
||||
- .libretro-windows-i686-msvc05-msys2-make-default
|
||||
- .core-defs
|
||||
|
||||
# Linux 64-bit
|
||||
libretro-build-linux-x64:
|
||||
extends:
|
||||
- .libretro-linux-x64-make-default
|
||||
- .core-defs
|
||||
|
||||
# MacOS 64-bit
|
||||
libretro-build-osx-x64:
|
||||
extends:
|
||||
- .libretro-osx-x64-make-default
|
||||
- .core-defs
|
||||
|
||||
# MacOS ARM 64-bit
|
||||
libretro-build-osx-arm64:
|
||||
extends:
|
||||
- .libretro-osx-arm64-make-default
|
||||
- .core-defs
|
||||
|
||||
################################### CELLULAR #################################
|
||||
# Android ARMv7a
|
||||
android-armeabi-v7a:
|
||||
extends:
|
||||
- .libretro-android-jni-armeabi-v7a
|
||||
- .core-defs
|
||||
|
||||
# Android ARMv8a
|
||||
android-arm64-v8a:
|
||||
extends:
|
||||
- .libretro-android-jni-arm64-v8a
|
||||
- .core-defs
|
||||
|
||||
# Android 64-bit x86
|
||||
android-x86_64:
|
||||
extends:
|
||||
- .libretro-android-jni-x86_64
|
||||
- .core-defs
|
||||
|
||||
# Android 32-bit x86
|
||||
android-x86:
|
||||
extends:
|
||||
- .libretro-android-jni-x86
|
||||
- .core-defs
|
||||
|
||||
# iOS 9
|
||||
libretro-build-ios9:
|
||||
extends:
|
||||
- .libretro-ios9-make-default
|
||||
- .core-defs
|
||||
|
||||
# iOS
|
||||
libretro-build-ios-arm64:
|
||||
extends:
|
||||
- .libretro-ios-arm64-make-default
|
||||
- .core-defs
|
||||
|
||||
# tvOS
|
||||
libretro-build-tvos-arm64:
|
||||
extends:
|
||||
- .libretro-tvos-arm64-make-default
|
||||
- .core-defs
|
||||
|
||||
################################### CONSOLES #################################
|
||||
# Dingux (GCW Zero)
|
||||
libretro-build-dingux-mips32:
|
||||
extends:
|
||||
- .libretro-dingux-mips32-make-default
|
||||
- .core-defs
|
||||
|
||||
# Nintendo 3DS
|
||||
libretro-build-ctr:
|
||||
extends:
|
||||
- .libretro-ctr-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
# Nintendo GameCube
|
||||
libretro-build-ngc:
|
||||
extends:
|
||||
- .libretro-ngc-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
# Nintendo Wii
|
||||
libretro-build-wii:
|
||||
extends:
|
||||
- .libretro-wii-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
# Nintendo Wii U
|
||||
libretro-build-wiiu:
|
||||
extends:
|
||||
- .libretro-wiiu-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
# Nintendo Switch
|
||||
libretro-build-libnx-aarch64:
|
||||
extends:
|
||||
- .libretro-libnx-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
# PlayStation 2
|
||||
libretro-build-ps2:
|
||||
extends:
|
||||
- .libretro-ps2-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
# PlayStation Vita
|
||||
libretro-build-vita:
|
||||
extends:
|
||||
- .libretro-vita-static-retroarch-master
|
||||
- .core-defs
|
||||
|
||||
#################################### MISC ##################################
|
||||
# Emscripten
|
||||
libretro-build-emscripten:
|
||||
extends:
|
||||
- .libretro-emscripten-static-retroarch-master
|
||||
- .core-defs
|
||||
0
.idea/.gitignore
generated
vendored
0
.idea/.gitignore
generated
vendored
2
.idea/Mu.iml
generated
2
.idea/Mu.iml
generated
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||
19
.idea/misc.xml
generated
19
.idea/misc.xml
generated
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="CidrRootsConfiguration">
|
||||
<sourceRoots>
|
||||
<file path="$PROJECT_DIR$/include" />
|
||||
<file path="$PROJECT_DIR$/src" />
|
||||
</sourceRoots>
|
||||
<excludeRoots>
|
||||
<file path="$PROJECT_DIR$/.github" />
|
||||
<file path="$PROJECT_DIR$/.idea" />
|
||||
<file path="$PROJECT_DIR$/bugs" />
|
||||
<file path="$PROJECT_DIR$/cmake-build-debug-visual-studio-1" />
|
||||
<file path="$PROJECT_DIR$/debugDumps" />
|
||||
<file path="$PROJECT_DIR$/images" />
|
||||
<file path="$PROJECT_DIR$/tools" />
|
||||
</excludeRoots>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Mu.iml" filepath="$PROJECT_DIR$/.idea/Mu.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,31 +0,0 @@
|
||||
cmake_minimum_required (VERSION 3.13)
|
||||
project(Mu
|
||||
VERSION 1.3.0
|
||||
DESCRIPTION "Classic Palm OS Emulator."
|
||||
HOMEPAGE_URL https://github.com/libretro/Mu
|
||||
LANGUAGES C CXX)
|
||||
|
||||
# Requires C99
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# To Emily...
|
||||
message("******************************")
|
||||
message("The continuation of the Mu along with the RetroArch Core is dedicated to")
|
||||
message("Emily (1998-2020), your friendship was very important to me and I hope")
|
||||
message("that you are resting well.")
|
||||
message(" -- Your friend, Stephanie")
|
||||
message("******************************")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_definitions(EMU_DEBUG=1)
|
||||
endif()
|
||||
|
||||
# Main project sources
|
||||
add_subdirectory(src)
|
||||
|
||||
# LibRetro Build
|
||||
add_subdirectory(libretroBuildSystem)
|
||||
|
||||
# QT Build
|
||||
add_subdirectory(qtBuildSystem)
|
||||
334
LICENSE
334
LICENSE
@@ -1,334 +0,0 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
Attribution-NonCommercial 3.0 Unported
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
|
||||
DAMAGES RESULTING FROM ITS USE.
|
||||
|
||||
License
|
||||
|
||||
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
|
||||
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
|
||||
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
|
||||
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
|
||||
|
||||
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
|
||||
TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
|
||||
BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
|
||||
CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
|
||||
CONDITIONS.
|
||||
|
||||
1. Definitions
|
||||
|
||||
a. "Adaptation" means a work based upon the Work, or upon the Work and
|
||||
other pre-existing works, such as a translation, adaptation,
|
||||
derivative work, arrangement of music or other alterations of a
|
||||
literary or artistic work, or phonogram or performance and includes
|
||||
cinematographic adaptations or any other form in which the Work may be
|
||||
recast, transformed, or adapted including in any form recognizably
|
||||
derived from the original, except that a work that constitutes a
|
||||
Collection will not be considered an Adaptation for the purpose of
|
||||
this License. For the avoidance of doubt, where the Work is a musical
|
||||
work, performance or phonogram, the synchronization of the Work in
|
||||
timed-relation with a moving image ("synching") will be considered an
|
||||
Adaptation for the purpose of this License.
|
||||
b. "Collection" means a collection of literary or artistic works, such as
|
||||
encyclopedias and anthologies, or performances, phonograms or
|
||||
broadcasts, or other works or subject matter other than works listed
|
||||
in Section 1(f) below, which, by reason of the selection and
|
||||
arrangement of their contents, constitute intellectual creations, in
|
||||
which the Work is included in its entirety in unmodified form along
|
||||
with one or more other contributions, each constituting separate and
|
||||
independent works in themselves, which together are assembled into a
|
||||
collective whole. A work that constitutes a Collection will not be
|
||||
considered an Adaptation (as defined above) for the purposes of this
|
||||
License.
|
||||
c. "Distribute" means to make available to the public the original and
|
||||
copies of the Work or Adaptation, as appropriate, through sale or
|
||||
other transfer of ownership.
|
||||
d. "Licensor" means the individual, individuals, entity or entities that
|
||||
offer(s) the Work under the terms of this License.
|
||||
e. "Original Author" means, in the case of a literary or artistic work,
|
||||
the individual, individuals, entity or entities who created the Work
|
||||
or if no individual or entity can be identified, the publisher; and in
|
||||
addition (i) in the case of a performance the actors, singers,
|
||||
musicians, dancers, and other persons who act, sing, deliver, declaim,
|
||||
play in, interpret or otherwise perform literary or artistic works or
|
||||
expressions of folklore; (ii) in the case of a phonogram the producer
|
||||
being the person or legal entity who first fixes the sounds of a
|
||||
performance or other sounds; and, (iii) in the case of broadcasts, the
|
||||
organization that transmits the broadcast.
|
||||
f. "Work" means the literary and/or artistic work offered under the terms
|
||||
of this License including without limitation any production in the
|
||||
literary, scientific and artistic domain, whatever may be the mode or
|
||||
form of its expression including digital form, such as a book,
|
||||
pamphlet and other writing; a lecture, address, sermon or other work
|
||||
of the same nature; a dramatic or dramatico-musical work; a
|
||||
choreographic work or entertainment in dumb show; a musical
|
||||
composition with or without words; a cinematographic work to which are
|
||||
assimilated works expressed by a process analogous to cinematography;
|
||||
a work of drawing, painting, architecture, sculpture, engraving or
|
||||
lithography; a photographic work to which are assimilated works
|
||||
expressed by a process analogous to photography; a work of applied
|
||||
art; an illustration, map, plan, sketch or three-dimensional work
|
||||
relative to geography, topography, architecture or science; a
|
||||
performance; a broadcast; a phonogram; a compilation of data to the
|
||||
extent it is protected as a copyrightable work; or a work performed by
|
||||
a variety or circus performer to the extent it is not otherwise
|
||||
considered a literary or artistic work.
|
||||
g. "You" means an individual or entity exercising rights under this
|
||||
License who has not previously violated the terms of this License with
|
||||
respect to the Work, or who has received express permission from the
|
||||
Licensor to exercise rights under this License despite a previous
|
||||
violation.
|
||||
h. "Publicly Perform" means to perform public recitations of the Work and
|
||||
to communicate to the public those public recitations, by any means or
|
||||
process, including by wire or wireless means or public digital
|
||||
performances; to make available to the public Works in such a way that
|
||||
members of the public may access these Works from a place and at a
|
||||
place individually chosen by them; to perform the Work to the public
|
||||
by any means or process and the communication to the public of the
|
||||
performances of the Work, including by public digital performance; to
|
||||
broadcast and rebroadcast the Work by any means including signs,
|
||||
sounds or images.
|
||||
i. "Reproduce" means to make copies of the Work by any means including
|
||||
without limitation by sound or visual recordings and the right of
|
||||
fixation and reproducing fixations of the Work, including storage of a
|
||||
protected performance or phonogram in digital form or other electronic
|
||||
medium.
|
||||
|
||||
2. Fair Dealing Rights. Nothing in this License is intended to reduce,
|
||||
limit, or restrict any uses free from copyright or rights arising from
|
||||
limitations or exceptions that are provided for in connection with the
|
||||
copyright protection under copyright law or other applicable laws.
|
||||
|
||||
3. License Grant. Subject to the terms and conditions of this License,
|
||||
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||
perpetual (for the duration of the applicable copyright) license to
|
||||
exercise the rights in the Work as stated below:
|
||||
|
||||
a. to Reproduce the Work, to incorporate the Work into one or more
|
||||
Collections, and to Reproduce the Work as incorporated in the
|
||||
Collections;
|
||||
b. to create and Reproduce Adaptations provided that any such Adaptation,
|
||||
including any translation in any medium, takes reasonable steps to
|
||||
clearly label, demarcate or otherwise identify that changes were made
|
||||
to the original Work. For example, a translation could be marked "The
|
||||
original work was translated from English to Spanish," or a
|
||||
modification could indicate "The original work has been modified.";
|
||||
c. to Distribute and Publicly Perform the Work including as incorporated
|
||||
in Collections; and,
|
||||
d. to Distribute and Publicly Perform Adaptations.
|
||||
|
||||
The above rights may be exercised in all media and formats whether now
|
||||
known or hereafter devised. The above rights include the right to make
|
||||
such modifications as are technically necessary to exercise the rights in
|
||||
other media and formats. Subject to Section 8(f), all rights not expressly
|
||||
granted by Licensor are hereby reserved, including but not limited to the
|
||||
rights set forth in Section 4(d).
|
||||
|
||||
4. Restrictions. The license granted in Section 3 above is expressly made
|
||||
subject to and limited by the following restrictions:
|
||||
|
||||
a. You may Distribute or Publicly Perform the Work only under the terms
|
||||
of this License. You must include a copy of, or the Uniform Resource
|
||||
Identifier (URI) for, this License with every copy of the Work You
|
||||
Distribute or Publicly Perform. You may not offer or impose any terms
|
||||
on the Work that restrict the terms of this License or the ability of
|
||||
the recipient of the Work to exercise the rights granted to that
|
||||
recipient under the terms of the License. You may not sublicense the
|
||||
Work. You must keep intact all notices that refer to this License and
|
||||
to the disclaimer of warranties with every copy of the Work You
|
||||
Distribute or Publicly Perform. When You Distribute or Publicly
|
||||
Perform the Work, You may not impose any effective technological
|
||||
measures on the Work that restrict the ability of a recipient of the
|
||||
Work from You to exercise the rights granted to that recipient under
|
||||
the terms of the License. This Section 4(a) applies to the Work as
|
||||
incorporated in a Collection, but this does not require the Collection
|
||||
apart from the Work itself to be made subject to the terms of this
|
||||
License. If You create a Collection, upon notice from any Licensor You
|
||||
must, to the extent practicable, remove from the Collection any credit
|
||||
as required by Section 4(c), as requested. If You create an
|
||||
Adaptation, upon notice from any Licensor You must, to the extent
|
||||
practicable, remove from the Adaptation any credit as required by
|
||||
Section 4(c), as requested.
|
||||
b. You may not exercise any of the rights granted to You in Section 3
|
||||
above in any manner that is primarily intended for or directed toward
|
||||
commercial advantage or private monetary compensation. The exchange of
|
||||
the Work for other copyrighted works by means of digital file-sharing
|
||||
or otherwise shall not be considered to be intended for or directed
|
||||
toward commercial advantage or private monetary compensation, provided
|
||||
there is no payment of any monetary compensation in connection with
|
||||
the exchange of copyrighted works.
|
||||
c. If You Distribute, or Publicly Perform the Work or any Adaptations or
|
||||
Collections, You must, unless a request has been made pursuant to
|
||||
Section 4(a), keep intact all copyright notices for the Work and
|
||||
provide, reasonable to the medium or means You are utilizing: (i) the
|
||||
name of the Original Author (or pseudonym, if applicable) if supplied,
|
||||
and/or if the Original Author and/or Licensor designate another party
|
||||
or parties (e.g., a sponsor institute, publishing entity, journal) for
|
||||
attribution ("Attribution Parties") in Licensor's copyright notice,
|
||||
terms of service or by other reasonable means, the name of such party
|
||||
or parties; (ii) the title of the Work if supplied; (iii) to the
|
||||
extent reasonably practicable, the URI, if any, that Licensor
|
||||
specifies to be associated with the Work, unless such URI does not
|
||||
refer to the copyright notice or licensing information for the Work;
|
||||
and, (iv) consistent with Section 3(b), in the case of an Adaptation,
|
||||
a credit identifying the use of the Work in the Adaptation (e.g.,
|
||||
"French translation of the Work by Original Author," or "Screenplay
|
||||
based on original Work by Original Author"). The credit required by
|
||||
this Section 4(c) may be implemented in any reasonable manner;
|
||||
provided, however, that in the case of a Adaptation or Collection, at
|
||||
a minimum such credit will appear, if a credit for all contributing
|
||||
authors of the Adaptation or Collection appears, then as part of these
|
||||
credits and in a manner at least as prominent as the credits for the
|
||||
other contributing authors. For the avoidance of doubt, You may only
|
||||
use the credit required by this Section for the purpose of attribution
|
||||
in the manner set out above and, by exercising Your rights under this
|
||||
License, You may not implicitly or explicitly assert or imply any
|
||||
connection with, sponsorship or endorsement by the Original Author,
|
||||
Licensor and/or Attribution Parties, as appropriate, of You or Your
|
||||
use of the Work, without the separate, express prior written
|
||||
permission of the Original Author, Licensor and/or Attribution
|
||||
Parties.
|
||||
d. For the avoidance of doubt:
|
||||
|
||||
i. Non-waivable Compulsory License Schemes. In those jurisdictions in
|
||||
which the right to collect royalties through any statutory or
|
||||
compulsory licensing scheme cannot be waived, the Licensor
|
||||
reserves the exclusive right to collect such royalties for any
|
||||
exercise by You of the rights granted under this License;
|
||||
ii. Waivable Compulsory License Schemes. In those jurisdictions in
|
||||
which the right to collect royalties through any statutory or
|
||||
compulsory licensing scheme can be waived, the Licensor reserves
|
||||
the exclusive right to collect such royalties for any exercise by
|
||||
You of the rights granted under this License if Your exercise of
|
||||
such rights is for a purpose or use which is otherwise than
|
||||
noncommercial as permitted under Section 4(b) and otherwise waives
|
||||
the right to collect royalties through any statutory or compulsory
|
||||
licensing scheme; and,
|
||||
iii. Voluntary License Schemes. The Licensor reserves the right to
|
||||
collect royalties, whether individually or, in the event that the
|
||||
Licensor is a member of a collecting society that administers
|
||||
voluntary licensing schemes, via that society, from any exercise
|
||||
by You of the rights granted under this License that is for a
|
||||
purpose or use which is otherwise than noncommercial as permitted
|
||||
under Section 4(c).
|
||||
e. Except as otherwise agreed in writing by the Licensor or as may be
|
||||
otherwise permitted by applicable law, if You Reproduce, Distribute or
|
||||
Publicly Perform the Work either by itself or as part of any
|
||||
Adaptations or Collections, You must not distort, mutilate, modify or
|
||||
take other derogatory action in relation to the Work which would be
|
||||
prejudicial to the Original Author's honor or reputation. Licensor
|
||||
agrees that in those jurisdictions (e.g. Japan), in which any exercise
|
||||
of the right granted in Section 3(b) of this License (the right to
|
||||
make Adaptations) would be deemed to be a distortion, mutilation,
|
||||
modification or other derogatory action prejudicial to the Original
|
||||
Author's honor and reputation, the Licensor will waive or not assert,
|
||||
as appropriate, this Section, to the fullest extent permitted by the
|
||||
applicable national law, to enable You to reasonably exercise Your
|
||||
right under Section 3(b) of this License (right to make Adaptations)
|
||||
but not otherwise.
|
||||
|
||||
5. Representations, Warranties and Disclaimer
|
||||
|
||||
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
|
||||
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
|
||||
KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
|
||||
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
|
||||
LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
|
||||
WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
|
||||
OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||
|
||||
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
|
||||
LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
|
||||
ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
|
||||
ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
|
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
7. Termination
|
||||
|
||||
a. This License and the rights granted hereunder will terminate
|
||||
automatically upon any breach by You of the terms of this License.
|
||||
Individuals or entities who have received Adaptations or Collections
|
||||
from You under this License, however, will not have their licenses
|
||||
terminated provided such individuals or entities remain in full
|
||||
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
|
||||
survive any termination of this License.
|
||||
b. Subject to the above terms and conditions, the license granted here is
|
||||
perpetual (for the duration of the applicable copyright in the Work).
|
||||
Notwithstanding the above, Licensor reserves the right to release the
|
||||
Work under different license terms or to stop distributing the Work at
|
||||
any time; provided, however that any such election will not serve to
|
||||
withdraw this License (or any other license that has been, or is
|
||||
required to be, granted under the terms of this License), and this
|
||||
License will continue in full force and effect unless terminated as
|
||||
stated above.
|
||||
|
||||
8. Miscellaneous
|
||||
|
||||
a. Each time You Distribute or Publicly Perform the Work or a Collection,
|
||||
the Licensor offers to the recipient a license to the Work on the same
|
||||
terms and conditions as the license granted to You under this License.
|
||||
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
|
||||
offers to the recipient a license to the original Work on the same
|
||||
terms and conditions as the license granted to You under this License.
|
||||
c. If any provision of this License is invalid or unenforceable under
|
||||
applicable law, it shall not affect the validity or enforceability of
|
||||
the remainder of the terms of this License, and without further action
|
||||
by the parties to this agreement, such provision shall be reformed to
|
||||
the minimum extent necessary to make such provision valid and
|
||||
enforceable.
|
||||
d. No term or provision of this License shall be deemed waived and no
|
||||
breach consented to unless such waiver or consent shall be in writing
|
||||
and signed by the party to be charged with such waiver or consent.
|
||||
e. This License constitutes the entire agreement between the parties with
|
||||
respect to the Work licensed here. There are no understandings,
|
||||
agreements or representations with respect to the Work not specified
|
||||
here. Licensor shall not be bound by any additional provisions that
|
||||
may appear in any communication from You. This License may not be
|
||||
modified without the mutual written agreement of the Licensor and You.
|
||||
f. The rights granted under, and the subject matter referenced, in this
|
||||
License were drafted utilizing the terminology of the Berne Convention
|
||||
for the Protection of Literary and Artistic Works (as amended on
|
||||
September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
|
||||
Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
|
||||
and the Universal Copyright Convention (as revised on July 24, 1971).
|
||||
These rights and subject matter take effect in the relevant
|
||||
jurisdiction in which the License terms are sought to be enforced
|
||||
according to the corresponding provisions of the implementation of
|
||||
those treaty provisions in the applicable national law. If the
|
||||
standard suite of rights granted under applicable copyright law
|
||||
includes additional rights not granted under this License, such
|
||||
additional rights are deemed to be included in the License; this
|
||||
License is not intended to restrict the license of any rights under
|
||||
applicable law.
|
||||
|
||||
|
||||
Creative Commons Notice
|
||||
|
||||
Creative Commons is not a party to this License, and makes no warranty
|
||||
whatsoever in connection with the Work. Creative Commons will not be
|
||||
liable to You or any party on any legal theory for any damages
|
||||
whatsoever, including without limitation any general, special,
|
||||
incidental or consequential damages arising in connection to this
|
||||
license. Notwithstanding the foregoing two (2) sentences, if Creative
|
||||
Commons has expressly identified itself as the Licensor hereunder, it
|
||||
shall have all rights and obligations of Licensor.
|
||||
|
||||
Except for the limited purpose of indicating to the public that the
|
||||
Work is licensed under the CCPL, Creative Commons does not authorize
|
||||
the use by either party of the trademark "Creative Commons" or any
|
||||
related trademark or logo of Creative Commons without the prior
|
||||
written consent of Creative Commons. Any permitted use will be in
|
||||
compliance with Creative Commons' then-current trademark usage
|
||||
guidelines, as may be published on its website or otherwise made
|
||||
available upon request from time to time. For the avoidance of doubt,
|
||||
this trademark restriction does not form part of the License.
|
||||
|
||||
Creative Commons may be contacted at https://creativecommons.org/.
|
||||
@@ -1,5 +1,5 @@
|
||||
T3 locks up endlessly checking TSC2101 interrupts
|
||||
QT release build is broken
|
||||
|
||||
Fixed:
|
||||
Trys to turn the CPU off when it shouldnt(kernel was crashing, the MMU from firebird is not working)
|
||||
68K Palm OS randomly locks up for 1-2 seconds(caused by interrupt handling code not turning the CPU back on for masked interrupts when it should because of faulty interrupt cacheing, Caused by commit: 1567cbce674741bc13be92b0847f59a5cc68335a)
|
||||
132
bugs/fixed/fixedUnimplementedHardware11292019.txt
Normal file
132
bugs/fixed/fixedUnimplementedHardware11292019.txt
Normal file
@@ -0,0 +1,132 @@
|
||||
memory dumping dosent work for OS 5 yet
|
||||
Endian compatibility is broken(the CPU state needs to be standardized)
|
||||
RetroArch port crashes on exit(needed to check if environ_cb returned true, switched to libretro-common filestreams too)
|
||||
make the headers belong to the main file of the target chip being emulated for specs
|
||||
remove specs folder
|
||||
UART1 USTCNT1
|
||||
trying to beam anything will lock up the OS
|
||||
Qt dosent have a hybrid file/folder selector so apps will always have to be launched from folders for now
|
||||
File Installer isnt working yet
|
||||
Qt GUI dosent resize properly with 320x320 framebuffer
|
||||
PLLFSR has a hack that makes busy wait loops finish faster by toggling the CLK32 bit on read, for power button issue(removed, power button works as expected if you wait at least 2 seconds before pushing it again(makes sence that it cnat read the new press while its turning off the CPU))
|
||||
(CPU)VFP(floating point) coprocessor for ARM(dont think the ARM Palms even used VFP)
|
||||
(Other)need to get rid of buffer_t, its not used much anyway
|
||||
ARM dynarec SIGSEGVs on exit(pushing play in the debugger still lets it continue, dont think this is a bug)
|
||||
(Feature)need to add FEATURE_DURABLE which will ignore CPU errors, increasing stability at the cost of bugginess
|
||||
(RetroArch port)set the alarm LED using retro_set_led_state_t on RetroArch
|
||||
(CPU I/O)SPI1 SPISPC register(this is just a clock divider used to slow transfers to allow the voltages to settle, since the emu has no voltages all transfers are just instant)
|
||||
(CPU)TCN2 is unimplemented and seems to be used by the same routines that turn the CPU off for sleep mode(it is implemented now and it wasn't the cause of the sleep mode issue)
|
||||
(CPU)SCR privilege violation doesnt trigger the same as on hardware(likely has to do with not emulating the unused chip selects)(I added those chip selects)
|
||||
(CPU)Trace T1 bit, should be unused by the OS and applications anyway(this was fixed long ago, don't know why it was still listed?)
|
||||
(SD Card)data blocks won't work properly when CRC checks are enabled
|
||||
(SD Card)the CRC of CSD and CID are invalid
|
||||
unemulated chip select(CSB1) privilege violation interrupts are not handled properly
|
||||
SD card can't be inserted in RetroArch port
|
||||
USB chip seems to share an interrupt with the SD card(the SD card interrupt is unimplemented at boot and triggers a printf over USB instead, if USB is not properly emulated that will cause a lock up)(enough of the USB is now emulated to prevent this)
|
||||
(SD Card)need to an input option for the write protect switch on the side of the SD card(will be fixed at input time since you can't flip it when in the slot)
|
||||
(SD Card)memory block ordering is broken
|
||||
(SD Card)block length is fixed at 512 right now(this is actually proper behavior for newer SDSC cards)
|
||||
(SD Card)need to dump valid SCR
|
||||
(SD Card)SEND_SCR may not be sending in the proper format(the return data format was not specified in the spec I read)(data packet format is working)
|
||||
SPI1(the SD card interface)(SPI1 master mode seems fully implemented now)
|
||||
SD card can't be read or written to by Palm OS(SPI transactions are going both ways now, some flash chip read commands are implemented too)
|
||||
(ADS7846)need to trigger a false PENIRQ interrupt on reading certain channels(this is being done now)
|
||||
(MakePalmBitmap)the small icons are corrupt
|
||||
(MakePalmBitmap)the non 16 bpp large icons are corrupt
|
||||
need to test if Port J Pin 3(SD card chip select) is attached to Port D Pin 5(SD Card Status(IRQ2))(pinouts.ru says chip select and card detect are the same line)(IRQ2 doesnt change when SD card chip select is toggled regardless of wether the card is inserted)
|
||||
the "Fatal Error" dialog reset button doesnt work, may not be a bug, could just an be issue with certain errors needing a full reset(its error dependent, one bug proved the other bug wasn't actually a bug)
|
||||
don't know if flushing the PWM1 FIFO sets all the bytes to 0x00, or just sets the read pointer to the write pointer preserving the newest sample and making the size 0(readPtr = writePtr has significantly cleaner audio then 0ing it out though(they sound the same now, this just masked the actual issue))
|
||||
edge triggered INT* don't clear on write to ISR when masked in IMR(I needed to use (ints & ~IMR) not (ints & IMR) which only triggers disable interrupts while blocking active ones)
|
||||
PDKBEN also has a hack for power on(its been removed)
|
||||
On hardware PDIRQEG seems not to actually work at all(CPUID:0x57000000)(it does)
|
||||
may need to trigger an interrupt if a IMR masked interrupt becomes unmasked and its bit is still set in IPR(already doing that)
|
||||
power button must be pushed twice to turn the CPU back on(when debugging it works the first time, then must be pushed twice to turn off instead of on)(this also occurs in the RetroArch build)
|
||||
the power button double press issue may be because the button map I am using was taken from POSE source, the power button may be mapped to other locations on the button matrix than expected
|
||||
if a sound interrupt is triggered while the button interrupt is disabled the button interrupt will still trigger(in galax game)(seems to be an issue with FIFOAV always = true hack and how INT_PWM1 needed to be cleared on read or write)
|
||||
SED1376 16 bpp mode is broken and crushed to the top of the screen
|
||||
audio can max out the resampler buffer, the max 1 FIFO sample can play is around 2.16 minutes(CLK32 / period(257) / clockDivider(16) / prescaler(128) / repeat(8))(257 * 16 * 128 * 8 / 32768=128.5 seconds)(safety check added, >= 1 second duty cycle is useless and will just make annoying cracks anyway)
|
||||
PWM1 output value is not a direct range cast of 0<->255 to 0<->32767, its additive, see properPwmSineWave.png
|
||||
inductor dosent properly drain when PWM1 gets disabled
|
||||
PWM1 FIFOAV is always set true
|
||||
may need to force sound generation until buffer is adequately filled when sound is on(not possible, INT_PWM1 is masked)
|
||||
if a timer triggers more than once per CLK32(> 32768 times a second) it will lose any triggers after the first and get out of sync(still not perfect but resolution is much higher)
|
||||
Peripheral Control Register, timer cascade mode
|
||||
MakePalmIcon 8bpp bitmaps have corrupt palettes
|
||||
missing home screen icons
|
||||
EMUCS memory range is unemulated(used for emu registers if enabled, invalid access otherwise)
|
||||
port g data bit 2 may need to be 0 to access ADS7846(it is)
|
||||
pen input
|
||||
pulling chip select low when high state likely resets the ADS7846 bit stream(this is currently being done when the SPI bus is enabled)(resetting on disable, that would make more sense because the chip needs to be read/written instantly once chip select is pulled low)
|
||||
From ADS7846 datasheet:Chip Select Input. Controls conversion timing and enables the serial input/output register. (this means the chip timing is likely reset when cs goes low)
|
||||
the ADS7846 is currently being reset every time the SPI is disabled and reenabled(happens when ADS7846 chip select is turned off, not on SPI enable)
|
||||
Port G SPI stuff(ADS7846 chip select was on port g)
|
||||
Edge triggered IRQ* interrupt pins may actually read the value of the interrupt instead of the pin value(IRQ* reads the pin, INT* still hasn't been tested yet)
|
||||
ADS7846 channels are not implemented properly in the emulator(works now)
|
||||
ADS7846 Channels 3 and 4(they need to be scaled differently)(works now)
|
||||
CPU32 table lookup opcodes(there is no CPU32)
|
||||
IRQ2 seems to not even be hooked up in IDA(IRQ2 is setup after boot by the SD driver, the kernels IRQ2 driver only sends a debug message over USB or serial)
|
||||
framebuffer accesses can cause a buffer overflow(this was always the case, its not a new bug)(just increased the buffer to an address line maskable size)
|
||||
chipselect mirroring is wrong(CS*0 and CS*1 are considered continuous when mapped with more address space than memory, mirroring is currently [CS*0, CS*1, repeat alternating till the end of address space] it should be [CS*0, repeat CS*0 until half way through CS* address space, CS*1, repeat CS*1 until end of CS* address space])
|
||||
the second line on all the chip selects is not properly emulated, they should be empty and trigger a bus error(except CSD1, it seems to follow different rules) but currently mirror the first half
|
||||
USB chip address range
|
||||
USB chip may be swapped into address space with a GPIO and reconfiguring CSC chip select
|
||||
the CSC address space is never accessed, this may be because the DRAM controller takes it over
|
||||
CSC0 and CSA1 ranges overlap, something specifically stated as what not to do(the CSA1 pin is disabled though)(its actually CSC that is disabled)
|
||||
CSC is owned by CSD for DRAM, CSA1 controls USB access
|
||||
All edge triggered interrupts(currently always level triggered)
|
||||
interrupt control register(ICR) edge trigger selects
|
||||
port d IRQ* bits edge triggered interrupt mode is not emulated
|
||||
edgeTriggeredInterruptLastValue may need to be locked when PLL is off(just checking if PLL is on before triggering an interrupt in edge triggered mode)
|
||||
Edge triggered interrupt seem needed for SD card(interrupt is disabled after card is inserted)(don't know if they are needed, but they are implemented now)
|
||||
on changing ICR all port d interrupts and IRQ5 need to be refreshed
|
||||
SD card can't be inserted or removed
|
||||
SD card has no error handling in save/load state
|
||||
there was what appeared to be memory corruption because a byte was incrementing and decrementing for loading and saving the same state but it was just the precision cast from uint64_t > double > uint64_t made it increment by 1
|
||||
STOP opcode may be causing issues with the power button(it may be setting a separate CPU disable option)(not a bug)
|
||||
add 320*320 frame buffer silkscreen, 2xBRZ should be able to make 320*320 version of the 160*160 silkscreen(not hooked up but one has been created)
|
||||
Tango icons don't grow enough with a big window
|
||||
a reset caused by the watchdog may cause undefined behavior(it just resets, same as if a reset opcode where called)
|
||||
CSD and CSC chaining to create a 16mb address space from 4x4mb chunks(this is just completely wrong, the address lines are controlled by the DRAM module that was unemulated)
|
||||
RAM wait states(not happening)
|
||||
All of DRAMMC
|
||||
need to investigate SDRAM registers
|
||||
Since chipselects must be aligned to there memory size the start address doesnt need to be subtracted from each address calculation
|
||||
PENIRQ can be read even when PFSEL bit 1 is false
|
||||
early on I swapped RGB16 R and B, the LUT register addresses for red and blue were swapped though, red actually is the top 5 bits
|
||||
Allow IMR to mask interrupts after they are created
|
||||
ADC7846 temperature sensors
|
||||
ADC7846 dock sensor
|
||||
storage RAM protect(already done from fixing chip select bits, ROP bit set in CSD, verified with hardware test)
|
||||
interrupt control register(ICR) POL5
|
||||
port g backlight state readback
|
||||
Timer capture events, I don't think there possible though with the Palms hardware(there not possible, the power button LED occupies the TIN pin which is required for capture events)
|
||||
port b pin 6 is xored with the power detection on the alarm/power LED, if docked it turns the LED off, if not docked it turns the LED on
|
||||
touch interrupt seems to not use IRQ5(it does, theres a test for it now)
|
||||
port d seems to allow using special function pins as inputs while active unlike other ports, this needs to be verified(verified by MC68VZ328UM.pdf Page 10-15)
|
||||
CPU_RUN_MODE is not preserved on save state and could allow executing after an address error if a save and load are performed(CPU_RUN_MODE is not used when address error is disabled)
|
||||
Bootloader memory access
|
||||
need to check REFREQ clock frequency in RTCCTL
|
||||
PLLCR CLKEN being off should also disable the SED1376 but this would require a bank refresh on writing to PLLCR
|
||||
proper clearing of timer interrupts
|
||||
PCTLR should not divide palmCrystalCycles or dmaclksPerClk32 can't use it(removed palmCrystalCycles from dmaclksPerClk32)
|
||||
if PCTLR divides the PLL it may also affect DMACLK, SYSCLK and the timers(it doesnt)
|
||||
timers shouldn't allow comp bits to be cleared until read with a 1 in them and should remain in interrupt state until they are cleared(the interrupt state part is unverified)
|
||||
SED1376 byte and word swap bits
|
||||
qt play pause icon not working for emu control button
|
||||
SED1376 register access
|
||||
SED1376 picture in picture registers
|
||||
PCTLR, can divide CPU speed by 1<->31
|
||||
Palm OS usage of the "rte" instruction is incompatible with the 68020, switch to 68000 core
|
||||
System Control Register, 0xXXFFF000 all upper banks are registers mode
|
||||
Port D keyboard enable register
|
||||
(HW verified)PDPOL inverts interrupts by inverting PDDATA bits, the data register is affected by PDPOL
|
||||
Endian safe savestates
|
||||
PLL Control Register, Wake Select
|
||||
(Resolved by MC68VZ328UM_CORRECTIONS datasheet, its 0xA28, 16 bits)The data sheet says LRRA is 0xFFFFFA29 and 0xFFFFFA28 but its only 8 bits?
|
||||
(All except edge triggered INT0/1/2/3 restart PLL)Check if interrupts restart PLL when its disabled
|
||||
Disabling PLL also turns off general purpose timer 1 and 2 unless they are set to use CLK32 as there source
|
||||
All chip select registers
|
||||
The boot memory mapping where ROM starts at 0x00000000 and RAM is swapped in
|
||||
Bits 15 and 14 of the chip selects, currently only the upper 16 bits are taken into account
|
||||
Supervisor only chip select bits
|
||||
RAM location and size setting, Dragonball VZ can set the page mapping SDCTRL(SDCTRL only sets external physical pins not RAM mapping)
|
||||
355
bugs/fixed/idleModeStackTrace.txt
Normal file
355
bugs/fixed/idleModeStackTrace.txt
Normal file
@@ -0,0 +1,355 @@
|
||||
Using uARM CPU core!(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 2 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0004, value:0x038FF000(printed 1 times)
|
||||
Set speed modeMISSING "\n"(printed 1 times)
|
||||
Someone tried to set processor power mode (cp14 reg7) to 0x00000003, PC:0x000003F8(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 36 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 43 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 45 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 47 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 48 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 51 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 52 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 53 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 57 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 78 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 79 set:1, PC:0x0000051C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 43 set:1, PC:0x0000053C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 45 set:4, PC:0x0000053C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 47 set:3, PC:0x0000053C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 78 set:4, PC:0x0000053C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0008(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0008, value:0x23DA23D2(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0008(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x000C, value:0x3FF1A441(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x000C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0010, value:0x7FF17FF1(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0010(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0014, value:0x00000001(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0014(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0028, value:0x00010504(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0028(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x002C, value:0x00010504(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x002C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0030, value:0x00010504(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0030(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0034, value:0x00010504(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0034(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0038, value:0x00004715(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0038(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x003C, value:0x00004715(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x003C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0004(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0004, value:0x00000018(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x001C, value:0x00000000(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0004(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0004, value:0x00010018(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0004(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0004, value:0x00010018(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0004, value:0x00018018(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0000, value:0x00000AC8(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0000, value:0x00000AC9(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0040, value:0x00000000(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x0004(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x0004, value:0x00118018(printed 1 times)
|
||||
Turned MMU on(printed 1 times)
|
||||
Unknown coprocessor instruction MCR 0E071F16(printed 2 times)
|
||||
Unknown coprocessor instruction MCR 0E071FB2(printed 1024 times)
|
||||
Unimplimented PXA260 GPIO 52 set:3, PC:0x00001128(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 52 set:3, PC:0x00001154(printed 1 times)
|
||||
Unknown coprocessor instruction MCR 0E071FB2(printed 2048 times)
|
||||
Unimplimented PXA260 GPIO 36 set:4, PC:0x2000636C(printed 1 times)
|
||||
Unimplemented TPS65010 register write, address:0x08, value:0x80, PC:0x20005B30(printed 10 times)
|
||||
Unimplemented TPS65010 register write, address:0x0D, value:0x00, PC:0x20005B30(printed 10 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x000C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x000C, value:0x3FF187A9(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x000C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 78 set:4, PC:0x2000631C(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 78 set:4, PC:0x20006328(printed 1 times)
|
||||
Unimplemented T3 SD chip write at address 0x0C, value:0x0014(printed 1 times)
|
||||
Unimplemented T3 SD chip read at address 0x0E(printed 1 times)
|
||||
Unimplemented T3 SD chip write at address 0x0C, value:0x0014(printed 1 times)
|
||||
Unimplemented T3 SD chip read at address 0x0E(printed 1 times)
|
||||
Unimplemented T3 SD chip read at address 0x0C(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 2 times)
|
||||
TSC2101 scan set to 0x0(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 2 times)
|
||||
TSC2101 config register writes not fully implemented(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 2 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC418(printed 1 times)
|
||||
Unknown coprocessor instruction MCR 0E071FB2(printed 16384 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:36(printed 1 times)
|
||||
Called from address:0x200B86C4(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:36, value:0(printed 1 times)
|
||||
Called from address:0x200B86DC(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 36 set:4, PC:0x200B1DC0(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:35(printed 1 times)
|
||||
Called from address:0x200B866C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:35, value:1(printed 1 times)
|
||||
Called from address:0x200B8688(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC7FC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC7FC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC7FC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC7FC(printed 1 times)
|
||||
Unimplemented TPS65010 register write, address:0x08, value:0x80, PC:0x200B5EFC(printed 10 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC7FC(printed 1 times)
|
||||
Unimplemented TPS65010 register write, address:0x0D, value:0x20, PC:0x200B5EFC(printed 10 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x000C(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register write:0x000C, value:0x3FF187A9(printed 1 times)
|
||||
Unimplimented 32 bit PXA260 MEMCTRL register read:0x000C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:78, value:0(printed 1 times)
|
||||
Called from address:0x200B6224(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 78 set:4, PC:0x200B1D70(printed 1 times)
|
||||
Unimplimented PXA260 GPIO 78 set:4, PC:0x200B1D7C(printed 1 times)
|
||||
Unimplemented T3 SD chip write at address 0x0C, value:0x0014(printed 1 times)
|
||||
Unimplemented T3 SD chip read at address 0x0E(printed 1 times)
|
||||
Unimplemented T3 SD chip write at address 0x0C, value:0x0014(printed 1 times)
|
||||
Unimplemented T3 SD chip read at address 0x0E(printed 1 times)
|
||||
Unimplemented T3 SD chip read at address 0x0C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:40, value:1(printed 1 times)
|
||||
Called from address:0x200B47CC(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:40, value:0(printed 1 times)
|
||||
Called from address:0x200B47E0(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:1(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:1(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
TSC2101 scan set to 0x0(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:1(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:1(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:1(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
TSC2101 config register writes not fully implemented(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:1(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
TSC2101 PINTDAV not fully implemented(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:24, value:0(printed 1 times)
|
||||
Called from address:0x200B47BC(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:33, value:1(printed 1 times)
|
||||
Called from address:0x200AAA0C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:0(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:10(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:11(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:33, value:0(printed 1 times)
|
||||
Called from address:0x200AAA58(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:19, value:1(printed 1 times)
|
||||
Called from address:0x200AAA0C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:0(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:10(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:11(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:19, value:0(printed 1 times)
|
||||
Called from address:0x200AAA58(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:20, value:1(printed 1 times)
|
||||
Called from address:0x200AAA0C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:0(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:10(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:11(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:20, value:0(printed 1 times)
|
||||
Called from address:0x200AAA58(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:21, value:1(printed 1 times)
|
||||
Called from address:0x200AAA0C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:0(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:10(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:11(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:21, value:0(printed 1 times)
|
||||
Called from address:0x200AAA58(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:22, value:1(printed 1 times)
|
||||
Called from address:0x200AAA0C(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:0(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:10(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "ReadGPIOPin", pin:11(printed 1 times)
|
||||
Called from address:0x200AAA34(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:22, value:0(printed 1 times)
|
||||
Called from address:0x200AAA58(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:1, value:0(printed 1 times)
|
||||
Called from address:0x200AC7FC(printed 1 times)
|
||||
TPS65010 DEFGPIO read, PC:0x200B610C(printed 10 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Called "WriteGPIOPinInvertedValue", pin:45, value:0(printed 1 times)
|
||||
Called from address:0x200ADD3C(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA174(printed 1 times)
|
||||
Jumped to:0x200BA170(printed 1 times)
|
||||
Jumped to:0x200BA16A(printed 1 times)
|
||||
Jumped to:0x200BA192(printed 1 times)
|
||||
Jumped to:0x2009F5E0(printed 1 times)//WriteBootVectorTable
|
||||
Jumped to:0x200BA196(printed 1 times)
|
||||
Jumped to:0x200BBF3A(printed 1 times)
|
||||
Jumped to:0x2009B524(printed 1 times)
|
||||
Jumped to:0x2009B540(printed 1 times)
|
||||
Jumped to:0x200A678C(printed 1 times)
|
||||
Jumped to:0x200BBF12(printed 1 times)
|
||||
Jumped to:0x00000008(printed 1 times)
|
||||
Jumped to:0x200C0FC4(printed 1 times)//\
|
||||
Jumped to:0x200C0FF8(printed 1 times)//|SWIVector handler
|
||||
Jumped to:0x200C102C(printed 1 times)///
|
||||
Jumped to:0x200C1048(printed 1 times)
|
||||
Jumped to:0x200C2114(printed 1 times)
|
||||
Jumped to:0x200BA2A4(printed 1 times)
|
||||
Jumped to:0x2009F850(printed 1 times)
|
||||
Jumped to:0x200C1130(printed 1 times)
|
||||
Jumped to:0x2009F638(printed 1 times)//\CallsEnterIdleModeLayer0, purpose unknown, dosent lock up
|
||||
Jumped to:0x2009F6E8(printed 1 times)///
|
||||
Jumped to:0x2009F6EC(printed 1 times)
|
||||
Jumped to:0x200BBF26(printed 1 times)
|
||||
Jumped to:0x200A67DC(printed 1 times)
|
||||
Jumped to:0x2009B554(printed 1 times)
|
||||
Jumped to:0x200A72CC(printed 1 times)//trying to load some module here but never gets to it
|
||||
Jumped to:0x200C3018(printed 1 times)//KALMutexCreate jumptable entry
|
||||
Jumped to:0x200C1F54(printed 1 times)//KALMutexCreate function stub
|
||||
Jumped to:0x200BC542(printed 1 times)//KALMutexCreate SVC call stub
|
||||
Jumped to:0x00000008(printed 1 times)//SVC call made, this is where things start to go bad
|
||||
Jumped to:0x200C0FC4(printed 1 times)//\
|
||||
Jumped to:0x200C0FF8(printed 1 times)//|
|
||||
Jumped to:0x200C102C(printed 1 times)//|SWIVector handler
|
||||
Jumped to:0x200C1118(printed 1 times)//|
|
||||
Jumped to:0x200C2444(printed 1 times)///
|
||||
Jumped to:0x200BA66A(printed 1 times)//KALMutexCreate real function
|
||||
Jumped to:0x200BA67A(printed 1 times)//KALMutexCreate availability checking loop
|
||||
Jumped to:0x200BA610(printed 1 times)//\
|
||||
Jumped to:0x200BA622(printed 1 times)//|
|
||||
Jumped to:0x200BA62C(printed 1 times)//|
|
||||
Jumped to:0x200BA636(printed 1 times)//|InitMutex
|
||||
Jumped to:0x200BA658(printed 1 times)//|
|
||||
Jumped to:0x200BA61E(printed 1 times)///
|
||||
Jumped to:0x200BA6A4(printed 1 times)//return to KALMutexCreate
|
||||
Jumped to:0x200C1130(printed 1 times)//return to SWIVector handler
|
||||
Jumped to:0x2009F638(printed 1 times)//\CallsEnterIdleModeLayer0, purpose unknown
|
||||
Jumped to:0x2009F6A8(printed 1 times)//|
|
||||
Jumped to:0x2009F678(printed 1 times)///
|
||||
Jumped to:0x200C2820(printed 1 times)//EnterIdleMode
|
||||
Called "EnterIdleMode", took 395292 jumps to reach this function(printed 1 times)
|
||||
Called from address:0x2009F68C(printed 1 times)
|
||||
Someone tried to set processor power mode (cp14 reg7) to 0x00000001, PC:0x200C283C(printed 1 times)
|
||||
@@ -1,7 +0,0 @@
|
||||
Cinco De Mayo(May 5th), 17:00 GMT, hopefully with some good ARM stuff(delayed again)
|
||||
Easter release, 17:00 GMT, hopefully with some good ARM stuff(delayed)
|
||||
|
||||
Done:
|
||||
Release at Christmas 17:00 GMT, 9:00 My time, 12:00 SquirrelJME devs time
|
||||
I post to r/emulation, Stephanie(SquirrelJME dev) posts to Twitter and Mastodon
|
||||
Sister projects with SquirrelJME: https://github.com/XerTheSquirrel/SquirrelJME
|
||||
@@ -60,139 +60,4 @@ T3 I2C currently has no ACK bits(should work without them its just inaccurate)(I
|
||||
T3 emulation attempts to set GPIO1(reset button) as an output
|
||||
GPIO lines from misc chips to CPU are not implemented
|
||||
PXA260 idle mode is unimplemented
|
||||
0x0E071F16 MCR P15, #0, R1, C7, C2, #5 is unimplemented along with several other unknown CP15 opcodes
|
||||
|
||||
|
||||
Fixed:
|
||||
memory dumping dosent work for OS 5 yet
|
||||
Endian compatibility is broken(the CPU state needs to be standardized)
|
||||
RetroArch port crashes on exit(needed to check if environ_cb returned true, switched to libretro-common filestreams too)
|
||||
make the headers belong to the main file of the target chip being emulated for specs
|
||||
remove specs folder
|
||||
UART1 USTCNT1
|
||||
trying to beam anything will lock up the OS
|
||||
Qt dosent have a hybrid file/folder selector so apps will always have to be launched from folders for now
|
||||
File Installer isnt working yet
|
||||
Qt GUI dosent resize properly with 320x320 framebuffer
|
||||
PLLFSR has a hack that makes busy wait loops finish faster by toggling the CLK32 bit on read, for power button issue(removed, power button works as expected if you wait at least 2 seconds before pushing it again(makes sence that it cnat read the new press while its turning off the CPU))
|
||||
(CPU)VFP(floating point) coprocessor for ARM(dont think the ARM Palms even used VFP)
|
||||
(Other)need to get rid of buffer_t, its not used much anyway
|
||||
ARM dynarec SIGSEGVs on exit(pushing play in the debugger still lets it continue, dont think this is a bug)
|
||||
(Feature)need to add FEATURE_DURABLE which will ignore CPU errors, increasing stability at the cost of bugginess
|
||||
(RetroArch port)set the alarm LED using retro_set_led_state_t on RetroArch
|
||||
(CPU I/O)SPI1 SPISPC register(this is just a clock divider used to slow transfers to allow the voltages to settle, since the emu has no voltages all transfers are just instant)
|
||||
(CPU)TCN2 is unimplemented and seems to be used by the same routines that turn the CPU off for sleep mode(it is implemented now and it wasn't the cause of the sleep mode issue)
|
||||
(CPU)SCR privilege violation doesnt trigger the same as on hardware(likely has to do with not emulating the unused chip selects)(I added those chip selects)
|
||||
(CPU)Trace T1 bit, should be unused by the OS and applications anyway(this was fixed long ago, don't know why it was still listed?)
|
||||
(SD Card)data blocks won't work properly when CRC checks are enabled
|
||||
(SD Card)the CRC of CSD and CID are invalid
|
||||
unemulated chip select(CSB1) privilege violation interrupts are not handled properly
|
||||
SD card can't be inserted in RetroArch port
|
||||
USB chip seems to share an interrupt with the SD card(the SD card interrupt is unimplemented at boot and triggers a printf over USB instead, if USB is not properly emulated that will cause a lock up)(enough of the USB is now emulated to prevent this)
|
||||
(SD Card)need to an input option for the write protect switch on the side of the SD card(will be fixed at input time since you can't flip it when in the slot)
|
||||
(SD Card)memory block ordering is broken
|
||||
(SD Card)block length is fixed at 512 right now(this is actually proper behavior for newer SDSC cards)
|
||||
(SD Card)need to dump valid SCR
|
||||
(SD Card)SEND_SCR may not be sending in the proper format(the return data format was not specified in the spec I read)(data packet format is working)
|
||||
SPI1(the SD card interface)(SPI1 master mode seems fully implemented now)
|
||||
SD card can't be read or written to by Palm OS(SPI transactions are going both ways now, some flash chip read commands are implemented too)
|
||||
(ADS7846)need to trigger a false PENIRQ interrupt on reading certain channels(this is being done now)
|
||||
(MakePalmBitmap)the small icons are corrupt
|
||||
(MakePalmBitmap)the non 16 bpp large icons are corrupt
|
||||
need to test if Port J Pin 3(SD card chip select) is attached to Port D Pin 5(SD Card Status(IRQ2))(pinouts.ru says chip select and card detect are the same line)(IRQ2 doesnt change when SD card chip select is toggled regardless of wether the card is inserted)
|
||||
the "Fatal Error" dialog reset button doesnt work, may not be a bug, could just an be issue with certain errors needing a full reset(its error dependent, one bug proved the other bug wasn't actually a bug)
|
||||
don't know if flushing the PWM1 FIFO sets all the bytes to 0x00, or just sets the read pointer to the write pointer preserving the newest sample and making the size 0(readPtr = writePtr has significantly cleaner audio then 0ing it out though(they sound the same now, this just masked the actual issue))
|
||||
edge triggered INT* don't clear on write to ISR when masked in IMR(I needed to use (ints & ~IMR) not (ints & IMR) which only triggers disable interrupts while blocking active ones)
|
||||
PDKBEN also has a hack for power on(its been removed)
|
||||
On hardware PDIRQEG seems not to actually work at all(CPUID:0x57000000)(it does)
|
||||
may need to trigger an interrupt if a IMR masked interrupt becomes unmasked and its bit is still set in IPR(already doing that)
|
||||
power button must be pushed twice to turn the CPU back on(when debugging it works the first time, then must be pushed twice to turn off instead of on)(this also occurs in the RetroArch build)
|
||||
the power button double press issue may be because the button map I am using was taken from POSE source, the power button may be mapped to other locations on the button matrix than expected
|
||||
if a sound interrupt is triggered while the button interrupt is disabled the button interrupt will still trigger(in galax game)(seems to be an issue with FIFOAV always = true hack and how INT_PWM1 needed to be cleared on read or write)
|
||||
SED1376 16 bpp mode is broken and crushed to the top of the screen
|
||||
audio can max out the resampler buffer, the max 1 FIFO sample can play is around 2.16 minutes(CLK32 / period(257) / clockDivider(16) / prescaler(128) / repeat(8))(257 * 16 * 128 * 8 / 32768=128.5 seconds)(safety check added, >= 1 second duty cycle is useless and will just make annoying cracks anyway)
|
||||
PWM1 output value is not a direct range cast of 0<->255 to 0<->32767, its additive, see properPwmSineWave.png
|
||||
inductor dosent properly drain when PWM1 gets disabled
|
||||
PWM1 FIFOAV is always set true
|
||||
may need to force sound generation until buffer is adequately filled when sound is on(not possible, INT_PWM1 is masked)
|
||||
if a timer triggers more than once per CLK32(> 32768 times a second) it will lose any triggers after the first and get out of sync(still not perfect but resolution is much higher)
|
||||
Peripheral Control Register, timer cascade mode
|
||||
MakePalmIcon 8bpp bitmaps have corrupt palettes
|
||||
missing home screen icons
|
||||
EMUCS memory range is unemulated(used for emu registers if enabled, invalid access otherwise)
|
||||
port g data bit 2 may need to be 0 to access ADS7846(it is)
|
||||
pen input
|
||||
pulling chip select low when high state likely resets the ADS7846 bit stream(this is currently being done when the SPI bus is enabled)(resetting on disable, that would make more sense because the chip needs to be read/written instantly once chip select is pulled low)
|
||||
From ADS7846 datasheet:Chip Select Input. Controls conversion timing and enables the serial input/output register. (this means the chip timing is likely reset when cs goes low)
|
||||
the ADS7846 is currently being reset every time the SPI is disabled and reenabled(happens when ADS7846 chip select is turned off, not on SPI enable)
|
||||
Port G SPI stuff(ADS7846 chip select was on port g)
|
||||
Edge triggered IRQ* interrupt pins may actually read the value of the interrupt instead of the pin value(IRQ* reads the pin, INT* still hasn't been tested yet)
|
||||
ADS7846 channels are not implemented properly in the emulator(works now)
|
||||
ADS7846 Channels 3 and 4(they need to be scaled differently)(works now)
|
||||
CPU32 table lookup opcodes(there is no CPU32)
|
||||
IRQ2 seems to not even be hooked up in IDA(IRQ2 is setup after boot by the SD driver, the kernels IRQ2 driver only sends a debug message over USB or serial)
|
||||
framebuffer accesses can cause a buffer overflow(this was always the case, its not a new bug)(just increased the buffer to an address line maskable size)
|
||||
chipselect mirroring is wrong(CS*0 and CS*1 are considered continuous when mapped with more address space than memory, mirroring is currently [CS*0, CS*1, repeat alternating till the end of address space] it should be [CS*0, repeat CS*0 until half way through CS* address space, CS*1, repeat CS*1 until end of CS* address space])
|
||||
the second line on all the chip selects is not properly emulated, they should be empty and trigger a bus error(except CSD1, it seems to follow different rules) but currently mirror the first half
|
||||
USB chip address range
|
||||
USB chip may be swapped into address space with a GPIO and reconfiguring CSC chip select
|
||||
the CSC address space is never accessed, this may be because the DRAM controller takes it over
|
||||
CSC0 and CSA1 ranges overlap, something specifically stated as what not to do(the CSA1 pin is disabled though)(its actually CSC that is disabled)
|
||||
CSC is owned by CSD for DRAM, CSA1 controls USB access
|
||||
All edge triggered interrupts(currently always level triggered)
|
||||
interrupt control register(ICR) edge trigger selects
|
||||
port d IRQ* bits edge triggered interrupt mode is not emulated
|
||||
edgeTriggeredInterruptLastValue may need to be locked when PLL is off(just checking if PLL is on before triggering an interrupt in edge triggered mode)
|
||||
Edge triggered interrupt seem needed for SD card(interrupt is disabled after card is inserted)(don't know if they are needed, but they are implemented now)
|
||||
on changing ICR all port d interrupts and IRQ5 need to be refreshed
|
||||
SD card can't be inserted or removed
|
||||
SD card has no error handling in save/load state
|
||||
there was what appeared to be memory corruption because a byte was incrementing and decrementing for loading and saving the same state but it was just the precision cast from uint64_t > double > uint64_t made it increment by 1
|
||||
STOP opcode may be causing issues with the power button(it may be setting a separate CPU disable option)(not a bug)
|
||||
add 320*320 frame buffer silkscreen, 2xBRZ should be able to make 320*320 version of the 160*160 silkscreen(not hooked up but one has been created)
|
||||
Tango icons don't grow enough with a big window
|
||||
a reset caused by the watchdog may cause undefined behavior(it just resets, same as if a reset opcode where called)
|
||||
CSD and CSC chaining to create a 16mb address space from 4x4mb chunks(this is just completely wrong, the address lines are controlled by the DRAM module that was unemulated)
|
||||
RAM wait states(not happening)
|
||||
All of DRAMMC
|
||||
need to investigate SDRAM registers
|
||||
Since chipselects must be aligned to there memory size the start address doesnt need to be subtracted from each address calculation
|
||||
PENIRQ can be read even when PFSEL bit 1 is false
|
||||
early on I swapped RGB16 R and B, the LUT register addresses for red and blue were swapped though, red actually is the top 5 bits
|
||||
Allow IMR to mask interrupts after they are created
|
||||
ADC7846 temperature sensors
|
||||
ADC7846 dock sensor
|
||||
storage RAM protect(already done from fixing chip select bits, ROP bit set in CSD, verified with hardware test)
|
||||
interrupt control register(ICR) POL5
|
||||
port g backlight state readback
|
||||
Timer capture events, I don't think there possible though with the Palms hardware(there not possible, the power button LED occupies the TIN pin which is required for capture events)
|
||||
port b pin 6 is xored with the power detection on the alarm/power LED, if docked it turns the LED off, if not docked it turns the LED on
|
||||
touch interrupt seems to not use IRQ5(it does, theres a test for it now)
|
||||
port d seems to allow using special function pins as inputs while active unlike other ports, this needs to be verified(verified by MC68VZ328UM.pdf Page 10-15)
|
||||
CPU_RUN_MODE is not preserved on save state and could allow executing after an address error if a save and load are performed(CPU_RUN_MODE is not used when address error is disabled)
|
||||
Bootloader memory access
|
||||
need to check REFREQ clock frequency in RTCCTL
|
||||
PLLCR CLKEN being off should also disable the SED1376 but this would require a bank refresh on writing to PLLCR
|
||||
proper clearing of timer interrupts
|
||||
PCTLR should not divide palmCrystalCycles or dmaclksPerClk32 can't use it(removed palmCrystalCycles from dmaclksPerClk32)
|
||||
if PCTLR divides the PLL it may also affect DMACLK, SYSCLK and the timers(it doesnt)
|
||||
timers shouldn't allow comp bits to be cleared until read with a 1 in them and should remain in interrupt state until they are cleared(the interrupt state part is unverified)
|
||||
SED1376 byte and word swap bits
|
||||
qt play pause icon not working for emu control button
|
||||
SED1376 register access
|
||||
SED1376 picture in picture registers
|
||||
PCTLR, can divide CPU speed by 1<->31
|
||||
Palm OS usage of the "rte" instruction is incompatible with the 68020, switch to 68000 core
|
||||
System Control Register, 0xXXFFF000 all upper banks are registers mode
|
||||
Port D keyboard enable register
|
||||
(HW verified)PDPOL inverts interrupts by inverting PDDATA bits, the data register is affected by PDPOL
|
||||
Endian safe savestates
|
||||
PLL Control Register, Wake Select
|
||||
(Resolved by MC68VZ328UM_CORRECTIONS datasheet, its 0xA28, 16 bits)The data sheet says LRRA is 0xFFFFFA29 and 0xFFFFFA28 but its only 8 bits?
|
||||
(All except edge triggered INT0/1/2/3 restart PLL)Check if interrupts restart PLL when its disabled
|
||||
Disabling PLL also turns off general purpose timer 1 and 2 unless they are set to use CLK32 as there source
|
||||
All chip select registers
|
||||
The boot memory mapping where ROM starts at 0x00000000 and RAM is swapped in
|
||||
Bits 15 and 14 of the chip selects, currently only the upper 16 bits are taken into account
|
||||
Supervisor only chip select bits
|
||||
RAM location and size setting, Dragonball VZ can set the page mapping SDCTRL(SDCTRL only sets external physical pins not RAM mapping)
|
||||
0x0E071F16 MCR P15, #0, R1, C7, C2, #5 is unimplemented along with several other unknown CP15 opcodes
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef H_ARMSNIPPETS
|
||||
#define H_ARMSNIPPETS
|
||||
|
||||
#define armloader_cb()
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
/* Declarations for asmcode.S */
|
||||
|
||||
#ifndef H_ASMCODE
|
||||
#define H_ASMCODE
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
// Supply the pointer to the instruction directly to avoid read_instruction
|
||||
void translation_enter(void *ptr) __asm__("translation_enter");
|
||||
#define TRANSLATION_ENTER_HAS_PTR 1
|
||||
#else
|
||||
void translation_enter() __asm__("translation_enter");
|
||||
#define TRANSLATION_ENTER_HAS_PTR 0
|
||||
#endif
|
||||
|
||||
// Jump to the translated code starting at ptr.
|
||||
// Checks for cycle_count_delta and exits if necessary.
|
||||
void translation_jmp(void *ptr) __asm__("translation_jmp");
|
||||
// Checks whether code at ptr is now translated and if so, jumps to it
|
||||
void translation_jmp_ptr(void *ptr) __asm__("translation_jmp_ptr");
|
||||
|
||||
void * FASTCALL read_instruction(uint32_t addr) __asm__("read_instruction");
|
||||
uint32_t FASTCALL read_byte(uint32_t addr) __asm__("read_byte");
|
||||
uint32_t FASTCALL read_half(uint32_t addr) __asm__("read_half");
|
||||
uint32_t FASTCALL read_word(uint32_t addr) __asm__("read_word");
|
||||
void FASTCALL write_byte(uint32_t addr, uint32_t value) __asm__("write_byte");
|
||||
void FASTCALL write_half(uint32_t addr, uint32_t value) __asm__("write_half");
|
||||
void FASTCALL write_word(uint32_t addr, uint32_t value) __asm__("write_word");
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
|
||||
// For some JITs there's in internal version called by JIT'ed code that can't be called
|
||||
// from outside the JIT'ed code
|
||||
uint32_t FASTCALL read_byte_asm(uint32_t addr) __asm__("read_byte_asm");
|
||||
uint32_t FASTCALL read_half_asm(uint32_t addr) __asm__("read_half_asm");
|
||||
uint32_t FASTCALL read_word_asm(uint32_t addr) __asm__("read_word_asm");
|
||||
void FASTCALL write_byte_asm(uint32_t addr, uint32_t value) __asm__("write_byte_asm");
|
||||
void FASTCALL write_half_asm(uint32_t addr, uint32_t value) __asm__("write_half_asm");
|
||||
void FASTCALL write_word_asm(uint32_t addr, uint32_t value) __asm__("write_word_asm");
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
#ifndef BITFIELD_H
|
||||
#define BITFIELD_H
|
||||
|
||||
/* Portable and safe implementation of C bitfields
|
||||
Source: http://blog.codef00.com/2014/12/06/portable-bitfields-using-c11/ */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//Mac OS RetroArch port is lacking <type_traits>
|
||||
template<bool B, class T, class F>
|
||||
struct typeConditional { typedef T type; };
|
||||
|
||||
template<class T, class F>
|
||||
struct typeConditional<false, T, F> { typedef F type; };
|
||||
|
||||
template <size_t LastBit>
|
||||
struct MinimumTypeHelper {
|
||||
typedef
|
||||
typename typeConditional<LastBit == 0 , void,
|
||||
typename typeConditional<LastBit <= 8 , uint8_t,
|
||||
typename typeConditional<LastBit <= 16, uint16_t,
|
||||
typename typeConditional<LastBit <= 32, uint32_t,
|
||||
typename typeConditional<LastBit <= 64, uint64_t,
|
||||
void>::type>::type>::type>::type>::type type;
|
||||
};
|
||||
|
||||
template <size_t Index, size_t Bits = 1>
|
||||
class BitField {
|
||||
private:
|
||||
enum {
|
||||
Mask = (1u << Bits) - 1u
|
||||
};
|
||||
|
||||
typedef typename MinimumTypeHelper<Index + Bits>::type T;
|
||||
public:
|
||||
template <class T2>
|
||||
BitField &operator=(T2 value) {
|
||||
value_ = (value_ & ~(Mask << Index)) | ((value & Mask) << Index);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
T2 as() { return (value_ >> Index) & Mask; }
|
||||
operator T() const { return (value_ >> Index) & Mask; }
|
||||
explicit operator bool() const { return value_ & (Mask << Index); }
|
||||
BitField &operator++() { return *this = *this + 1; }
|
||||
T operator++(int) { T r = *this; ++*this; return r; }
|
||||
BitField &operator--() { return *this = *this - 1; }
|
||||
T operator--(int) { T r = *this; ++*this; return r; }
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
|
||||
template <size_t Index>
|
||||
class BitField<Index, 1> {
|
||||
private:
|
||||
enum {
|
||||
Bits = 1,
|
||||
Mask = 0x01
|
||||
};
|
||||
|
||||
typedef typename MinimumTypeHelper<Index + Bits>::type T;
|
||||
public:
|
||||
template <typename T2>
|
||||
T2 as() { return (value_ >> Index) & Mask; }
|
||||
BitField &operator=(bool value) {
|
||||
value_ = (value_ & ~(Mask << Index)) | (value << Index);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return value_ & (Mask << Index); }
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
#endif // BITFIELD_H
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/* Declarations for cpu.c */
|
||||
|
||||
#ifndef CPU_H
|
||||
#define CPU_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fixings.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__pragma(pack(push, 1))
|
||||
#endif
|
||||
|
||||
typedef struct arm_state { // Remember to update asmcode.S if this gets rearranged
|
||||
uint32_t reg[16]; // Registers for current mode.
|
||||
|
||||
uint32_t cpsr_low28; // CPSR bits 0-27
|
||||
uint8_t cpsr_n; // CPSR bit 31
|
||||
uint8_t cpsr_z; // CPSR bit 30
|
||||
uint8_t cpsr_c; // CPSR bit 29
|
||||
uint8_t cpsr_v; // CPSR bit 28
|
||||
|
||||
#if defined(__arm__)
|
||||
uint32_t cpsr_flags; // Only used in ARM translations
|
||||
#endif
|
||||
|
||||
/* CP15 registers */
|
||||
uint32_t control;
|
||||
uint32_t translation_table_base;
|
||||
uint32_t domain_access_control;
|
||||
uint8_t data_fault_status, instruction_fault_status, pad1, pad2; // pad1 and pad2 for better alignment
|
||||
uint32_t fault_address;
|
||||
|
||||
uint32_t r8_usr[5], r13_usr[2];
|
||||
uint32_t r8_fiq[5], r13_fiq[2], spsr_fiq;
|
||||
uint32_t r13_irq[2], spsr_irq;
|
||||
uint32_t r13_svc[2], spsr_svc;
|
||||
uint32_t r13_abt[2], spsr_abt;
|
||||
uint32_t r13_und[2], spsr_und;
|
||||
|
||||
uint8_t interrupts;
|
||||
uint32_t cpu_events_state; // Only used for suspend and resume!
|
||||
}
|
||||
|
||||
#if !defined(__EMSCRIPTEN__) && !defined(_MSC_VER)
|
||||
__attribute__((packed))
|
||||
#endif
|
||||
arm_state;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__pragma(pack(pop))
|
||||
#endif
|
||||
|
||||
extern struct arm_state arm __asm__("arm");
|
||||
|
||||
#define MODE_USR 0x10
|
||||
#define MODE_FIQ 0x11
|
||||
#define MODE_IRQ 0x12
|
||||
#define MODE_SVC 0x13
|
||||
#define MODE_ABT 0x17
|
||||
#define MODE_UND 0x1B
|
||||
#define MODE_SYS 0x1F
|
||||
#define PRIVILEGED_MODE() (arm.cpsr_low28 & 3)
|
||||
#define USER_MODE() (!(arm.cpsr_low28 & 3))
|
||||
|
||||
#define EX_RESET 0
|
||||
#define EX_UNDEFINED 1
|
||||
#define EX_SWI 2
|
||||
#define EX_PREFETCH_ABORT 3
|
||||
#define EX_DATA_ABORT 4
|
||||
#define EX_IRQ 6
|
||||
#define EX_FIQ 7
|
||||
|
||||
#define current_instr_size ((arm.cpsr_low28 & 0x20) ? 2 /* thumb */ : 4)
|
||||
|
||||
// Needed for the assembler calling convention
|
||||
#ifdef __i386__
|
||||
#ifdef FASTCALL
|
||||
#undef FASTCALL
|
||||
#endif
|
||||
#define FASTCALL __attribute__((fastcall))
|
||||
#else
|
||||
#define FASTCALL
|
||||
#endif
|
||||
|
||||
void cpu_int_check();
|
||||
uint32_t get_cpsr() __asm__("get_cpsr");
|
||||
void set_cpsr_full(uint32_t cpsr);
|
||||
void FASTCALL set_cpsr(uint32_t cpsr, uint32_t mask);
|
||||
uint32_t get_spsr();
|
||||
void FASTCALL set_spsr(uint32_t cpsr, uint32_t mask);
|
||||
uint32_t *ptr_spsr();
|
||||
uint32_t get_cpsr_flags();
|
||||
void set_cpsr_flags(uint32_t flags) __asm__("set_cpsr_flags");
|
||||
void cpu_exception(int type);
|
||||
void fix_pc_for_fault();
|
||||
void *try_ptr(uint32_t addr);
|
||||
void cpu_interpret_instruction(uint32_t insn);
|
||||
void cpu_arm_loop();
|
||||
void cpu_thumb_loop();
|
||||
typedef void fault_proc(uint32_t mva, uint8_t status);
|
||||
fault_proc prefetch_abort, data_abort __asm__("data_abort");
|
||||
void undefined_instruction();
|
||||
|
||||
uint32_t reg(uint8_t i);
|
||||
uint32_t reg_pc(uint8_t i);
|
||||
uint32_t reg_pc_mem(uint8_t i);
|
||||
void set_reg(uint8_t i, uint32_t value);
|
||||
void set_reg_pc(uint8_t i, uint32_t value);
|
||||
void set_reg_bx(uint8_t i, uint32_t value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,157 +0,0 @@
|
||||
#ifndef CPUDEFS_H
|
||||
#define CPUDEFS_H
|
||||
|
||||
#include "bitfield.h"
|
||||
|
||||
// Structure of instructions, enums etc.
|
||||
|
||||
union Instruction {
|
||||
uint32_t raw;
|
||||
|
||||
BitField<28, 4> cond;
|
||||
BitField<0, 28> rest;
|
||||
|
||||
union {
|
||||
BitField<24> l;
|
||||
BitField<0, 24> immed;
|
||||
} branch;
|
||||
|
||||
union {
|
||||
BitField<0, 4> rm;
|
||||
BitField<5> l;
|
||||
} bx;
|
||||
|
||||
union {
|
||||
BitField<21, 4> op;
|
||||
BitField<20> s;
|
||||
BitField<16, 4> rn;
|
||||
BitField<12, 4> rd;
|
||||
BitField<25> imm;
|
||||
|
||||
// If imm
|
||||
BitField<0, 8> immed_8;
|
||||
BitField<8, 4> rotate_imm;
|
||||
// else
|
||||
BitField<4> reg_shift;
|
||||
BitField<0, 4> rm;
|
||||
BitField<5, 2> shift;
|
||||
// If reg_shift
|
||||
BitField<8, 4> rs;
|
||||
// else
|
||||
BitField<7, 5> shift_imm;
|
||||
} data_proc; // ADD, MOV, etc.
|
||||
|
||||
union {
|
||||
BitField<25> not_imm;
|
||||
BitField<24> p;
|
||||
BitField<23> u;
|
||||
BitField<22> b;
|
||||
BitField<21> w;
|
||||
BitField<20> l;
|
||||
BitField<16, 4> rn;
|
||||
BitField<12, 4> rd;
|
||||
|
||||
// If not_imm == 0
|
||||
BitField<0, 12> immed;
|
||||
// else
|
||||
BitField<0, 4> rm;
|
||||
BitField<5, 2> shift;
|
||||
BitField<7, 5> shift_imm;
|
||||
} mem_proc; // LDR, STRB, etc.
|
||||
|
||||
union {
|
||||
BitField<24> p;
|
||||
BitField<23> u;
|
||||
BitField<22> i;
|
||||
BitField<21> w;
|
||||
BitField<20> l;
|
||||
BitField<16, 4> rn;
|
||||
BitField<12, 4> rd;
|
||||
|
||||
BitField<6> s;
|
||||
BitField<5> h;
|
||||
|
||||
// If i
|
||||
BitField<8, 4> immed_h;
|
||||
BitField<0, 4> immed_l;
|
||||
// else
|
||||
BitField<0, 4> rm;
|
||||
} mem_proc2; // LDRH, STRSH, etc.
|
||||
|
||||
union {
|
||||
BitField<23> l;
|
||||
BitField<21> a;
|
||||
BitField<20> s;
|
||||
|
||||
BitField<8, 4> rs;
|
||||
BitField<0, 4> rm;
|
||||
|
||||
// If l
|
||||
BitField<16, 4> rdhi;
|
||||
BitField<12, 4> rdlo;
|
||||
// else
|
||||
BitField<16, 4> rd;
|
||||
BitField<12, 4> rn;
|
||||
} mult;
|
||||
|
||||
union {
|
||||
BitField<22> r;
|
||||
BitField<12, 4> rd;
|
||||
} mrs;
|
||||
|
||||
union {
|
||||
BitField<24> p;
|
||||
BitField<23> u;
|
||||
BitField<22> s;
|
||||
BitField<21> w;
|
||||
BitField<20> l;
|
||||
BitField<16, 4> rn;
|
||||
BitField<0, 16> reglist;
|
||||
} mem_multi;
|
||||
};
|
||||
|
||||
enum Condition {
|
||||
CC_EQ=0, CC_NE,
|
||||
CC_CS, CC_CC,
|
||||
CC_MI, CC_PL,
|
||||
CC_VS, CC_VC,
|
||||
CC_HI, CC_LS,
|
||||
CC_GE, CC_LT,
|
||||
CC_GT, CC_LE,
|
||||
CC_AL, CC_NV
|
||||
};
|
||||
|
||||
enum ShiftType {
|
||||
SH_LSL=0,
|
||||
SH_LSR,
|
||||
SH_ASR,
|
||||
SH_ROR // RRX if count == 0
|
||||
};
|
||||
|
||||
enum DataOp {
|
||||
OP_AND=0,
|
||||
OP_EOR,
|
||||
OP_SUB,
|
||||
OP_RSB,
|
||||
OP_ADD,
|
||||
OP_ADC,
|
||||
OP_SBC,
|
||||
OP_RSC,
|
||||
OP_TST,
|
||||
OP_TEQ,
|
||||
OP_CMP,
|
||||
OP_CMN,
|
||||
OP_ORR,
|
||||
OP_MOV,
|
||||
OP_BIC,
|
||||
OP_MVN
|
||||
};
|
||||
|
||||
// Defined in arm_interpreter.cpp
|
||||
void do_arm_instruction(Instruction i);
|
||||
// Defined in coproc.cpp
|
||||
void do_cp15_instruction(Instruction i);
|
||||
void do_cp14_instruction(Instruction i);
|
||||
|
||||
#endif // CPUDEFS_H
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* Declarations for debug.c */
|
||||
#ifndef H_DEBUG
|
||||
#define H_DEBUG
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
extern FILE *debugger_input;
|
||||
#define gdb_connected false
|
||||
#define in_debugger false
|
||||
#define rdbg_port 0
|
||||
*/
|
||||
|
||||
enum DBG_REASON {
|
||||
DBG_USER,
|
||||
DBG_EXCEPTION,
|
||||
DBG_EXEC_BREAKPOINT,
|
||||
DBG_READ_BREAKPOINT,
|
||||
DBG_WRITE_BREAKPOINT,
|
||||
};
|
||||
|
||||
/*
|
||||
void *virt_mem_ptr(uint32_t addr, uint32_t size);
|
||||
void backtrace(uint32_t fp);
|
||||
int process_debug_cmd(char *cmdline);
|
||||
void debugger(enum DBG_REASON reason, uint32_t addr);
|
||||
void rdebug_recv(void);
|
||||
bool rdebug_bind(unsigned int port);
|
||||
void rdebug_quit();
|
||||
*/
|
||||
#define debugger(x, y)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef H_EMU
|
||||
#define H_EMU
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
|
||||
#include "../emulator.h"
|
||||
#include "../portability.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline uint16_t BSWAP16(uint16_t x) { return x << 8 | x >> 8; }
|
||||
#define BSWAP32(x) __builtin_bswap32(x)
|
||||
|
||||
extern int cycle_count_delta __asm__("cycle_count_delta");
|
||||
extern uint32_t cpu_events __asm__("cpu_events");
|
||||
#define EVENT_IRQ 1
|
||||
#define EVENT_FIQ 2
|
||||
#define EVENT_RESET 4
|
||||
#define EVENT_DEBUG_STEP 8
|
||||
#define EVENT_WAITING 16
|
||||
|
||||
// Settings
|
||||
extern bool exiting;
|
||||
extern bool do_translate;
|
||||
|
||||
enum { LOG_CPU, LOG_IO, LOG_FLASH, LOG_INTS, LOG_ICOUNT, LOG_USB, LOG_GDB, MAX_LOG };
|
||||
#define LOG_TYPE_TBL "CIFQ#UG"
|
||||
//void logprintf(int type, const char *str, ...);
|
||||
//void emuprintf(const char *format, ...);
|
||||
#define logprintf(type, ...) debugLog(__VA_ARGS__)
|
||||
#define emuprintf(...) debugLog(__VA_ARGS__)
|
||||
|
||||
//void warn(const char *fmt, ...);
|
||||
//__attribute__((noreturn)) void error(const char *fmt, ...);
|
||||
#define warn(...) debugLog(__VA_ARGS__)
|
||||
#define error(...) abort()
|
||||
|
||||
extern jmp_buf restart_after_exception;
|
||||
|
||||
// GUI callbacks
|
||||
#define gui_debug_printf(...) debugLog(__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef LITERALPOOL_H
|
||||
#define LITERALPOOL_H
|
||||
|
||||
/* Code shared by various translators, this file keeps the
|
||||
arch-independant parts. */
|
||||
|
||||
struct LiteralRef {
|
||||
void *inst;
|
||||
uintptr_t value;
|
||||
};
|
||||
|
||||
static constexpr size_t MAX_LITERALS = 1024;
|
||||
static LiteralRef literals[MAX_LITERALS];
|
||||
static size_t literals_count = 0;
|
||||
|
||||
void literalpool_add(uintptr_t value)
|
||||
{
|
||||
if(literals_count >= MAX_LITERALS)
|
||||
{
|
||||
literals_count = 0; // Otherwise it won't ever be empty again
|
||||
error("Literal pool full, please increase the size");
|
||||
return;
|
||||
}
|
||||
|
||||
literals[literals_count++] = LiteralRef { .inst = translate_current,
|
||||
.value = value };
|
||||
}
|
||||
|
||||
/* Function implemented by the architecture.
|
||||
It needs to iterate through all elements in literals until literals_count,
|
||||
emit the literal into a suitable location and fixup all instructions that
|
||||
reference it. If alignment is not an issue, certain values can be optimized,
|
||||
but in such cases the loading instruction and the literal pool need to agree.
|
||||
It then needs to reset literals_count to 0. */
|
||||
void literalpool_fill();
|
||||
|
||||
#endif //LITERALPOOL_H
|
||||
@@ -1,84 +0,0 @@
|
||||
/* Declarations for memory.c */
|
||||
|
||||
#ifndef H_MEM
|
||||
#define H_MEM
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MEM_MAXSIZE (80*1024*1024) // also defined as RAM_FLAGS in asmcode.S
|
||||
|
||||
extern uint8_t (*read_byte_map[64])(uint32_t addr);
|
||||
extern uint16_t (*read_half_map[64])(uint32_t addr);
|
||||
extern uint32_t (*read_word_map[64])(uint32_t addr);
|
||||
extern void (*write_byte_map[64])(uint32_t addr, uint8_t value);
|
||||
extern void (*write_half_map[64])(uint32_t addr, uint16_t value);
|
||||
extern void (*write_word_map[64])(uint32_t addr, uint32_t value);
|
||||
|
||||
// Must be allocated below 2GB (see comments for mmu.c)
|
||||
extern uint8_t *mem_and_flags;
|
||||
struct mem_area_desc {
|
||||
uint32_t base, size;
|
||||
uint8_t *ptr;
|
||||
};
|
||||
extern struct mem_area_desc mem_areas[2];
|
||||
void *phys_mem_ptr(uint32_t addr, uint32_t size);
|
||||
uint32_t phys_mem_addr(void *ptr);
|
||||
|
||||
/* Each word of memory has a flag word associated with it. For fast access,
|
||||
* flags are located at a constant offset from the memory data itself.
|
||||
*
|
||||
* These can't be per-byte because a translation index wouldn't fit then.
|
||||
* This does mean byte/halfword accesses have to mask off the low bits to
|
||||
* check flags, but the alternative would be another 32MB of memory overhead. */
|
||||
#define RAM_FLAGS(memptr) (*(uint32_t *)((uint8_t *)(memptr) + MEM_MAXSIZE))
|
||||
|
||||
#define RF_READ_BREAKPOINT 1
|
||||
#define RF_WRITE_BREAKPOINT 2
|
||||
#define RF_EXEC_BREAKPOINT 4
|
||||
#define RF_EXEC_DEBUG_NEXT 8
|
||||
#define RF_CODE_EXECUTED 16
|
||||
#define RF_CODE_TRANSLATED 32
|
||||
#define RF_CODE_NO_TRANSLATE 64
|
||||
#define RF_READ_ONLY 128
|
||||
#define RF_ARMLOADER_CB 256
|
||||
#define RFS_TRANSLATION_INDEX 9
|
||||
|
||||
#define DO_READ_ACTION (RF_READ_BREAKPOINT)
|
||||
#define DO_WRITE_ACTION (RF_WRITE_BREAKPOINT | RF_CODE_TRANSLATED | RF_CODE_NO_TRANSLATE | RF_CODE_EXECUTED)
|
||||
#define DONT_TRANSLATE (RF_EXEC_BREAKPOINT | RF_EXEC_DEBUG_NEXT | RF_CODE_TRANSLATED | RF_CODE_NO_TRANSLATE)
|
||||
|
||||
uint8_t bad_read_byte(uint32_t addr);
|
||||
uint16_t bad_read_half(uint32_t addr);
|
||||
uint32_t bad_read_word(uint32_t addr);
|
||||
void bad_write_byte(uint32_t addr, uint8_t value);
|
||||
void bad_write_half(uint32_t addr, uint16_t value);
|
||||
void bad_write_word(uint32_t addr, uint32_t value);
|
||||
|
||||
void write_action(void *ptr) __asm__("write_action");
|
||||
void read_action(void *ptr) __asm__("read_action");
|
||||
|
||||
uint8_t memory_read_byte(uint32_t addr);
|
||||
uint16_t memory_read_half(uint32_t addr);
|
||||
uint32_t memory_read_word(uint32_t addr);
|
||||
void memory_write_byte(uint32_t addr, uint8_t value);
|
||||
void memory_write_half(uint32_t addr, uint16_t value);
|
||||
void memory_write_word(uint32_t addr, uint32_t value);
|
||||
|
||||
uint32_t FASTCALL mmio_read_byte(uint32_t addr) __asm__("mmio_read_byte");
|
||||
uint32_t FASTCALL mmio_read_half(uint32_t addr) __asm__("mmio_read_half");
|
||||
uint32_t FASTCALL mmio_read_word(uint32_t addr) __asm__("mmio_read_word");
|
||||
void FASTCALL mmio_write_byte(uint32_t addr, uint32_t value) __asm__("mmio_write_byte");
|
||||
void FASTCALL mmio_write_half(uint32_t addr, uint32_t value) __asm__("mmio_write_half");
|
||||
void FASTCALL mmio_write_word(uint32_t addr, uint32_t value) __asm__("mmio_write_word");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
#ifndef H_MMU
|
||||
#define H_MMU
|
||||
|
||||
#include "cpu.h"
|
||||
#include "emu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Translate a VA to a PA, using a page table lookup */
|
||||
uint32_t mmu_translate(uint32_t addr, bool writing, fault_proc *fault, uint8_t *s_status);
|
||||
|
||||
/* Used for t-type (usermode-like) access */
|
||||
void mmu_check_priv(uint32_t addr, bool writing);
|
||||
|
||||
/* addr_cache is used to cache the translation of VA to PA per page.
|
||||
* It has two entries per page (1k), one for reading and one for writing.
|
||||
* The format for 32-bit x86 with JIT is different to minimize the needed
|
||||
* registers in the x86 memory access functions and won't work for all
|
||||
* platforms:
|
||||
*
|
||||
* a) Pointer entry
|
||||
* The result of adding the virtual address (VA) to the entry has bit 31
|
||||
* clear, and that sum is a pointer to within mem_and_flags.
|
||||
* It would be cleaner to just use bit 0 or 1 to distinguish this case, but
|
||||
* this way we can simultaneously check both that this is a pointer entry,
|
||||
* and that the address is aligned, with a single bit test instruction.
|
||||
* b) Physical address entry
|
||||
* VA + entry has bit 31 set, and the entry (not the sum) has bit 22 clear.
|
||||
* Bits 0-21 contain the difference between virtual and physical address.
|
||||
* c) Invalid entry
|
||||
* VA + entry has bit 31 set, entry has bit 22 set. Entry is invalid and
|
||||
* addr_cache_miss must be called.
|
||||
*
|
||||
* In all other cases the format is simpler:
|
||||
* a) Pointer entry: Bit 0 clear, rest difference to pointer to start of physical page
|
||||
* b) Physical entry: Bit 0 set, Bit 1 clear, rest difference to physical address
|
||||
* c) Invalid entry: Bit 0 set, Bit 1 set
|
||||
*/
|
||||
|
||||
#define AC_NUM_ENTRIES (((1ull << 32) >> 10) * 2)
|
||||
typedef uint8_t *ac_entry;
|
||||
extern ac_entry *addr_cache __asm__("addr_cache");
|
||||
|
||||
#if defined(__i386__) && !defined(NO_TRANSLATION)
|
||||
#define AC_SET_ENTRY_PTR(entry, va, ptr) \
|
||||
entry = (ptr) - (va);
|
||||
#define AC_NOT_PTR 0x80000000
|
||||
#define AC_INVALID (1 << 22)
|
||||
#define AC_SET_ENTRY_PHYS(entry, va, pa) \
|
||||
entry = (ac_entry)(((pa) - (va)) >> 10); \
|
||||
entry += (~(uintptr_t)((va) + entry) & AC_NOT_PTR);
|
||||
#define AC_SET_ENTRY_INVALID(entry, va) \
|
||||
entry = (ac_entry)(AC_INVALID); \
|
||||
entry += (~(uintptr_t)((va) + entry) & AC_NOT_PTR);
|
||||
#else
|
||||
#define AC_SET_ENTRY_PTR(entry, va, ptr) \
|
||||
entry = (ptr) - (va);
|
||||
#define AC_NOT_PTR 0x1
|
||||
#define AC_INVALID 0x2
|
||||
#define AC_FLAGS 0x3
|
||||
#define AC_SET_ENTRY_PHYS(entry, va, pa) \
|
||||
entry = (ac_entry)(((pa) - (va)) | AC_NOT_PTR);
|
||||
#define AC_SET_ENTRY_INVALID(entry, va) \
|
||||
entry = (ac_entry)(AC_INVALID | AC_NOT_PTR);
|
||||
#endif
|
||||
|
||||
bool addr_cache_pagefault(void *addr);
|
||||
void *addr_cache_miss(uint32_t addr, bool writing, fault_proc *fault) __asm__("addr_cache_miss");
|
||||
void addr_cache_flush(void);
|
||||
void mmu_dump_tables(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef OS_H
|
||||
#define OS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef IS_IOS_BUILD
|
||||
int iOS_is_debugger_attached();
|
||||
#endif
|
||||
|
||||
#if !defined(__x86_64__) && !defined(NO_TRANSLATION) && (defined(_WIN32) || defined(WIN32))
|
||||
#define OS_HAS_PAGEFAULT_HANDLER 1
|
||||
#else
|
||||
#define OS_HAS_PAGEFAULT_HANDLER 0
|
||||
#endif
|
||||
|
||||
void *os_reserve(size_t size);
|
||||
void *os_alloc_executable(size_t size);
|
||||
void os_free(void *ptr, size_t size);
|
||||
|
||||
#if OS_HAS_PAGEFAULT_HANDLER
|
||||
// The Win32 mechanism to handle pagefaults uses SEH, which requires a linked
|
||||
// list of handlers on the stack. The frame has to stay alive on the stack and
|
||||
// armed during all addr_cache accesses.
|
||||
|
||||
typedef struct { void *prev, *function; } os_exception_frame_t;
|
||||
void os_faulthandler_arm(os_exception_frame_t *frame);
|
||||
void os_faulthandler_unarm(os_exception_frame_t *frame);
|
||||
|
||||
void *os_commit(void *addr, size_t size);
|
||||
void *os_sparse_commit(void *page, size_t size);
|
||||
void os_sparse_decommit(void *page, size_t size);
|
||||
#endif
|
||||
|
||||
void addr_cache_init();
|
||||
void addr_cache_deinit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
/* Declarations for translate.c */
|
||||
|
||||
#ifndef H_TRANSLATE
|
||||
#define H_TRANSLATE
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fixings.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__pragma(pack(push, 1))
|
||||
#endif
|
||||
|
||||
struct translation {
|
||||
uintptr_t unused;
|
||||
void** jump_table;
|
||||
uint32_t *start_ptr;
|
||||
uint32_t *end_ptr;
|
||||
}
|
||||
#if !defined(_MSC_VER)
|
||||
__attribute__((packed))
|
||||
#endif
|
||||
;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__pragma(pack(pop))
|
||||
#endif
|
||||
|
||||
extern struct translation translation_table[] __asm__("translation_table");
|
||||
#define INSN_BUFFER_SIZE 0x1000000
|
||||
|
||||
bool translate_init();
|
||||
void translate_deinit();
|
||||
void translate(uint32_t start_pc, uint32_t *insnp);
|
||||
void flush_translations();
|
||||
void invalidate_translation(int index);
|
||||
void translate_fix_pc();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef UARM_GLUE_H
|
||||
#define UARM_GLUE_H
|
||||
|
||||
#include "CPU_2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
Boolean uArmMemAccess(struct ArmCpu* cpu, void* buf, UInt32 vaddr, UInt8 size, Boolean write, Boolean priviledged, UInt8* fsr); //read/write
|
||||
Boolean uArmHypercall(struct ArmCpu* cpu);//return true if handled
|
||||
void uArmEmulErr (struct ArmCpu* cpu, const char* err_str);
|
||||
void uArmSetFaultAddr(struct ArmCpu* cpu, UInt32 adr, UInt8 faultStatus);
|
||||
|
||||
void uArmInitCpXX(ArmCpu* cpu);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// Created by xer on 2021-07-15.
|
||||
//
|
||||
|
||||
#ifndef MU_FIXINGS_H
|
||||
#define MU_FIXINGS_H
|
||||
|
||||
/* Fixes for Visual Studio. */
|
||||
#if defined(_MSC_VER)
|
||||
/* Prevent any assembly references from being used. */
|
||||
#define __asm__(what)
|
||||
|
||||
/* GCC's __builtin_popcount */
|
||||
#include <intrin.h>
|
||||
#define __builtin_popcount __popcnt
|
||||
#endif
|
||||
|
||||
#endif // MU_FIXINGS_H
|
||||
@@ -1,185 +0,0 @@
|
||||
#include "../w86l488.h"
|
||||
|
||||
static uint8_t pxa260_io_read_byte(uint32_t addr){
|
||||
debugLog("Invalid 8 bit PXA260 register read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static uint16_t pxa260_io_read_half(uint32_t addr){
|
||||
debugLog("Invalid 16 bit PXA260 register read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
static uint32_t pxa260_io_read_word(uint32_t addr){
|
||||
uint32_t out;
|
||||
|
||||
switch(addr >> 16){
|
||||
case PXA260_CLOCK_MANAGER_BASE >> 16:
|
||||
pxa260pwrClkPrvClockMgrMemAccessF(&pxa260PwrClk, addr, 4, false, &out);
|
||||
break;
|
||||
case PXA260_POWER_MANAGER_BASE >> 16:
|
||||
pxa260pwrClkPrvPowerMgrMemAccessF(&pxa260PwrClk, addr, 4, false, &out);
|
||||
break;
|
||||
case PXA260_TIMR_BASE >> 16:
|
||||
pxa260timrPrvMemAccessF(&pxa260Timer, addr, 4, false, &out);
|
||||
break;
|
||||
case PXA260_GPIO_BASE >> 16:
|
||||
pxa260gpioPrvMemAccessF(&pxa260Gpio, addr, 4, false, &out);
|
||||
break;
|
||||
case PXA260_I2C_BASE >> 16:
|
||||
out = pxa260I2cReadWord(addr);
|
||||
break;
|
||||
case PXA260_SSP_BASE >> 16:
|
||||
out = pxa260SspReadWord(addr);
|
||||
break;
|
||||
case PXA260_UDC_BASE >> 16:
|
||||
out = pxa260UdcReadWord(addr);
|
||||
break;
|
||||
case PXA260_IC_BASE >> 16:
|
||||
pxa260icPrvMemAccessF(&pxa260Ic, addr, 4, false, &out);
|
||||
break;
|
||||
|
||||
case PXA260_DMA_BASE >> 16:
|
||||
case PXA260_RTC_BASE >> 16:
|
||||
case PXA260_FFUART_BASE >> 16:
|
||||
case PXA260_BTUART_BASE >> 16:
|
||||
case PXA260_STUART_BASE >> 16:
|
||||
//need to implement these
|
||||
debugLog("Unimplemented 32 bit PXA260 register read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
out = 0x00000000;
|
||||
break;
|
||||
|
||||
default:
|
||||
debugLog("Invalid 32 bit PXA260 register read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
out = 0x00000000;
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void pxa260_io_write_byte(uint32_t addr, uint8_t value){
|
||||
debugLog("Invalid 8 bit PXA260 register write:0x%08X, value:0x%02X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_io_write_half(uint32_t addr, uint16_t value){
|
||||
debugLog("Invalid 16 bit PXA260 register write:0x%08X, value:0x%04X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_io_write_word(uint32_t addr, uint32_t value){
|
||||
switch(addr >> 16){
|
||||
case PXA260_CLOCK_MANAGER_BASE >> 16:
|
||||
pxa260pwrClkPrvClockMgrMemAccessF(&pxa260PwrClk, addr, 4, true, &value);
|
||||
break;
|
||||
case PXA260_POWER_MANAGER_BASE >> 16:
|
||||
pxa260pwrClkPrvPowerMgrMemAccessF(&pxa260PwrClk, addr, 4, true, &value);
|
||||
break;
|
||||
case PXA260_TIMR_BASE >> 16:
|
||||
pxa260timrPrvMemAccessF(&pxa260Timer, addr, 4, true, &value);
|
||||
break;
|
||||
case PXA260_GPIO_BASE >> 16:
|
||||
pxa260gpioPrvMemAccessF(&pxa260Gpio, addr, 4, true, &value);
|
||||
break;
|
||||
case PXA260_I2C_BASE >> 16:
|
||||
pxa260I2cWriteWord(addr, value);
|
||||
break;
|
||||
case PXA260_SSP_BASE >> 16:
|
||||
pxa260SspWriteWord(addr, value);
|
||||
break;
|
||||
case PXA260_UDC_BASE >> 16:
|
||||
pxa260UdcWriteWord(addr, value);
|
||||
break;
|
||||
case PXA260_IC_BASE >> 16:
|
||||
pxa260icPrvMemAccessF(&pxa260Ic, addr, 4, true, &value);
|
||||
break;
|
||||
|
||||
case PXA260_DMA_BASE >> 16:
|
||||
case PXA260_RTC_BASE >> 16:
|
||||
case PXA260_FFUART_BASE >> 16:
|
||||
case PXA260_BTUART_BASE >> 16:
|
||||
case PXA260_STUART_BASE >> 16:
|
||||
//need to implement these
|
||||
debugLog("Unimplemented 32 bit PXA260 register write:0x%08X, value:0x%08X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
break;
|
||||
|
||||
default:
|
||||
debugLog("Invalid 32 bit PXA260 register write:0x%08X, value:0x%08X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pxa260_lcd_read_word(uint32_t addr){
|
||||
uint32_t out;
|
||||
|
||||
pxa260lcdPrvMemAccessF(&pxa260Lcd, addr, 4, false, &out);
|
||||
debugLog("32 bit PXA260 LCD register read:0x%08X\n", addr);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void pxa260_lcd_write_word(uint32_t addr, uint32_t value){
|
||||
pxa260lcdPrvMemAccessF(&pxa260Lcd, addr, 4, true, &value);
|
||||
debugLog("32 bit PXA260 LCD register write:0x%08X, value:0x%08X\n", addr, value);
|
||||
}
|
||||
|
||||
static uint8_t pxa260_pcmcia0_read_byte(uint32_t addr){
|
||||
debugLog("PCMCIA0 8 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static uint16_t pxa260_pcmcia0_read_half(uint32_t addr){
|
||||
debugLog("PCMCIA0 16 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
static uint32_t pxa260_pcmcia0_read_word(uint32_t addr){
|
||||
debugLog("PCMCIA0 32 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia0_write_byte(uint32_t addr, uint8_t value){
|
||||
debugLog("PCMCIA0 8 bit write:0x%08X, value:0x%02X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia0_write_half(uint32_t addr, uint16_t value){
|
||||
debugLog("PCMCIA0 16 bit write:0x%08X, value:0x%04X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia0_write_word(uint32_t addr, uint32_t value){
|
||||
debugLog("PCMCIA0 32 bit write:0x%08X, value:0x%08X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static uint8_t pxa260_pcmcia1_read_byte(uint32_t addr){
|
||||
debugLog("PCMCIA1 8 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static uint16_t pxa260_pcmcia1_read_half(uint32_t addr){
|
||||
debugLog("PCMCIA1 16 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
static uint32_t pxa260_pcmcia1_read_word(uint32_t addr){
|
||||
debugLog("PCMCIA1 32 bit read:0x%08X, PC:0x%08X\n", addr, pxa260GetPc());
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia1_write_byte(uint32_t addr, uint8_t value){
|
||||
debugLog("PCMCIA1 8 bit write:0x%08X, value:0x%02X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia1_write_half(uint32_t addr, uint16_t value){
|
||||
debugLog("PCMCIA1 16 bit write:0x%08X, value:0x%04X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static void pxa260_pcmcia1_write_word(uint32_t addr, uint32_t value){
|
||||
debugLog("PCMCIA1 32 bit write:0x%08X, value:0x%08X, PC:0x%08X\n", addr, value, pxa260GetPc());
|
||||
}
|
||||
|
||||
static uint16_t pxa260_static_chip_select_2_read_half(uint32_t addr){
|
||||
return w86l488Read16(addr & 0x0E);
|
||||
}
|
||||
|
||||
static void pxa260_static_chip_select_2_write_half(uint32_t addr, uint16_t value){
|
||||
w86l488Write16(addr & 0x0E, value);
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef PXA260_CPU_H
|
||||
#define PXA260_CPU_H
|
||||
|
||||
#include "pxa260_types.h"
|
||||
|
||||
#if defined(EMU_NO_SAFETY)
|
||||
#include "../armv5te/emu.h"
|
||||
#include "../armv5te/cpu.h"
|
||||
|
||||
#define cpuGetRegExternal(x, regNum) reg_pc(regNum)
|
||||
#define cpuSetReg(x, regNum, value) set_reg(regNum, value)
|
||||
|
||||
#define cpuIrq(x, fiq, raise) (raise ? (cpu_events |= (fiq ? EVENT_FIQ : EVENT_IRQ)) : (cpu_events &= (fiq ? ~EVENT_FIQ : ~EVENT_IRQ)))
|
||||
#else
|
||||
#include "../armv5te/uArm/CPU_2.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// Created by stephanie on 6/14/24.
|
||||
//
|
||||
|
||||
#ifndef MU_SERIAL_H
|
||||
#define MU_SERIAL_H
|
||||
|
||||
#include "emulator.h"
|
||||
|
||||
/**
|
||||
* Opens and initializes the serial port.
|
||||
*
|
||||
* @param path The path of the serial port.
|
||||
* @since 2024/06/14
|
||||
*/
|
||||
void mu_serial_open_and_init(const char* path);
|
||||
|
||||
#endif // MU_SERIAL_H
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef TUNGSTEN_T3_BUS_H
|
||||
#define TUNGSTEN_T3_BUS_H
|
||||
|
||||
#define PXA260_BANK_SCOOT 26
|
||||
#define PXA260_NUM_BANKS(areaSize) (((areaSize) >> PXA260_BANK_SCOOT) + ((areaSize) & ((1 << PXA260_BANK_SCOOT) - 1) ? 1 : 0))
|
||||
#define PXA260_START_BANK(address) ((address) >> PXA260_BANK_SCOOT)
|
||||
#define PXA260_END_BANK(address, size) (PXA260_START_BANK(address) + PXA260_NUM_BANKS(size) - 1)
|
||||
#define PXA260_BANK_IN_RANGE(bank, address, size) ((bank) >= PXA260_START_BANK(address) && (bank) <= PXA260_END_BANK(address, size))
|
||||
#define PXA260_BANK_ADDRESS(bank) ((bank) << PXA260_BANK_SCOOT)
|
||||
#define PXA260_TOTAL_MEMORY_BANKS (1 << (32 - PXA260_BANK_SCOOT))//64 banks for *_BANK_SCOOT = 26
|
||||
|
||||
#define PXA260_ROM_START_ADDRESS 0x00000000
|
||||
#define PXA260_RAM_START_ADDRESS 0xA0000000
|
||||
#define TUNGSTEN_T3_W86L488_START_ADDRESS 0x08000000
|
||||
#define PXA260_PCMCIA0_START_ADDRESS 0x20000000
|
||||
#define PXA260_PCMCIA1_START_ADDRESS 0x30000000
|
||||
#define TUNGSTEN_T3_ROM_SIZE (16 * 0x100000)//16mb ROM
|
||||
#define TUNGSTEN_T3_RAM_SIZE (64 * 0x100000)//64mb RAM
|
||||
#define TUNGSTEN_T3_W86L488_SIZE 0x04000000
|
||||
#define PXA260_PCMCIA0_SIZE 0x10000000
|
||||
#define PXA260_PCMCIA1_SIZE 0x10000000
|
||||
|
||||
#endif
|
||||
@@ -1,54 +0,0 @@
|
||||
add_library(mu_libretro SHARED
|
||||
libretro.c
|
||||
cursors.c
|
||||
miniz.c
|
||||
libretro-common/compat/compat_strl.c
|
||||
libretro-common/compat/compat_posix_string.c
|
||||
libretro-common/compat/fopen_utf8.c
|
||||
libretro-common/encodings/encoding_utf.c
|
||||
libretro-common/memmap/memmap.c
|
||||
libretro-common/streams/file_stream.c
|
||||
libretro-common/string/stdstring.c
|
||||
libretro-common/vfs/vfs_implementation.c)
|
||||
|
||||
# Remove the "lib" prefix always, RetroArch does not name in this way
|
||||
set_target_properties(mu_libretro PROPERTIES PREFIX "")
|
||||
|
||||
# Define these
|
||||
target_compile_definitions(mu_libretro PUBLIC
|
||||
__LIBRETRO__=1)
|
||||
|
||||
# Bring all the sub-modules as needed
|
||||
target_link_libraries(mu_libretro
|
||||
MuCore)
|
||||
|
||||
# Include the required includes
|
||||
target_include_directories(mu_libretro PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/include"
|
||||
"libretro-common/include")
|
||||
|
||||
# Custom launching the core, tries to find RetroArch on the system
|
||||
## Determine RetroArch directory
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
set(MU_LIBRETRO_EXTENSION ".exe")
|
||||
|
||||
if (EXISTS "$ENV{APPDATA}/RetroArch")
|
||||
set(MU_LIBRETRO_DIR "$ENV{APPDATA}/RetroArch")
|
||||
endif()
|
||||
else()
|
||||
find_program(RETROARCH_APP retroarch)
|
||||
if(RETROARCH_APP)
|
||||
get_filename_component(MU_LIBRETRO_DIR "${RETROARCH_APP}" DIRECTORY)
|
||||
endif()
|
||||
|
||||
set(MU_LIBRETRO_EXTENSION "")
|
||||
endif()
|
||||
|
||||
## Target to run RetroArch with the Mu Core
|
||||
if(DEFINED MU_LIBRETRO_DIR)
|
||||
add_custom_target(RetroArch
|
||||
DEPENDS mu_libretro
|
||||
COMMAND "${MU_LIBRETRO_DIR}/retroarch${MU_LIBRETRO_EXTENSION}" "-v" "-L" "$<TARGET_FILE:mu_libretro>"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
COMMENT "Starting RetroArch with Mu")
|
||||
endif()
|
||||
@@ -87,6 +87,7 @@ else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
endif
|
||||
|
||||
#CC = gcc
|
||||
#CXX = g++
|
||||
TARGET_NAME := mu
|
||||
LIBM = -lm
|
||||
|
||||
@@ -127,28 +128,13 @@ ifeq ($(arch),ppc)
|
||||
CFLAGS += -D__ppc__ -DMSB_FIRST -DWORDS_BIGENDIAN=1
|
||||
endif
|
||||
OSXVER = $(shell sw_vers -productVersion | cut -d. -f 2)
|
||||
OSX_LT_MAVERICKS = $(shell (( $(OSXVER) <= 9)) && echo "YES")
|
||||
OSX_GT_MOJAVE = $(shell (( $(OSXVER) >= 14)) && echo "YES")
|
||||
|
||||
ifeq ($(OSX_LT_MAVERICKS),"YES")
|
||||
fpic += -mmacosx-version-min=10.5
|
||||
else
|
||||
ifneq ($(OSX_GT_MOJAVE),YES)
|
||||
#this breaks compiling on Mac OS Mojave
|
||||
fpic += -mmacosx-version-min=10.1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(OSX_GT_MOJAVE),YES)
|
||||
#this breaks compiling on Mac OS Mojave
|
||||
fpic += -mmacosx-version-min=10.1
|
||||
endif
|
||||
SHARED := -dynamiclib
|
||||
|
||||
ifeq ($(CROSS_COMPILE),1)
|
||||
TARGET_RULE = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)
|
||||
CFLAGS += $(TARGET_RULE)
|
||||
CPPFLAGS += $(TARGET_RULE)
|
||||
CXXFLAGS += $(TARGET_RULE)
|
||||
LDFLAGS += $(TARGET_RULE)
|
||||
endif
|
||||
|
||||
# iOS
|
||||
else ifneq (,$(findstring ios,$(platform)))
|
||||
EXT ?= dylib
|
||||
@@ -186,8 +172,6 @@ else ifeq ($(platform), tvos-arm64)
|
||||
ifeq ($(IOSSDK),)
|
||||
IOSSDK := $(shell xcodebuild -version -sdk appletvos Path)
|
||||
endif
|
||||
CC = clang -arch arm64 -isysroot $(IOSSDK)
|
||||
CXX = clang++ -arch arm64 -isysroot $(IOSSDK)
|
||||
|
||||
# Theos iOS
|
||||
else ifeq ($(platform), theos_ios)
|
||||
@@ -210,15 +194,33 @@ else ifeq ($(platform), qnx)
|
||||
AR = qcc -Vgcc_ntoarmv7le
|
||||
CFLAGS += -D__BLACKBERRY_QNX__
|
||||
|
||||
# PS3
|
||||
else ifeq ($(platform), ps3)
|
||||
EXT = a
|
||||
TARGET := $(TARGET_NAME)_libretro_ps3.$(EXT)
|
||||
CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
|
||||
AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
|
||||
CFLAGS += -D__ppc__ -DMSB_FIRST -DWORDS_BIGENDIAN=1
|
||||
STATIC_LINKING = 1
|
||||
STATIC_LINKING_LINK = 1
|
||||
|
||||
# PS3 (SNC)
|
||||
else ifeq ($(platform), sncps3)
|
||||
EXT = a
|
||||
TARGET := $(TARGET_NAME)_libretro_ps3.$(EXT)
|
||||
CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
|
||||
AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
|
||||
CFLAGS += -D__ppc__ -DMSB_FIRST -DWORDS_BIGENDIAN=1
|
||||
STATIC_LINKING = 1
|
||||
STATIC_LINKING_LINK = 1
|
||||
|
||||
# Lightweight PS3 Homebrew SDK
|
||||
else ifneq (,$(filter $(platform), ps3 psl1ght))
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).a
|
||||
CC = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)gcc$(EXE_EXT)
|
||||
AR = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)ar$(EXE_EXT)
|
||||
ifeq ($(platform), psl1ght)
|
||||
CFLAGS += -D__PSL1GHT__
|
||||
endif
|
||||
CFLAGS += -D__ppc__ -DMSB_FIRST -DWORDS_BIGENDIAN=1 -D__PS3__
|
||||
else ifeq ($(platform), psl1ght)
|
||||
EXT = a
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).$(EXT)
|
||||
CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT)
|
||||
AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT)
|
||||
CFLAGS += -D__ppc__ -DMSB_FIRST -DWORDS_BIGENDIAN=1
|
||||
STATIC_LINKING = 1
|
||||
STATIC_LINKING_LINK = 1
|
||||
|
||||
@@ -393,9 +395,7 @@ else ifneq (,$(findstring armv,$(platform)))
|
||||
# Emscripten
|
||||
else ifeq ($(platform), emscripten)
|
||||
TARGET := $(TARGET_NAME)_libretro_emscripten.bc
|
||||
AR=emar
|
||||
STATIC_LINKING = 1
|
||||
STATIC_LINKING_LINK = 1
|
||||
|
||||
# GCW0
|
||||
else ifeq ($(platform), gcw0)
|
||||
@@ -452,16 +452,6 @@ else ifeq ($(platform), xbox1_msvc2003)
|
||||
STATIC_LINKING = 1
|
||||
STATIC_LINKING_LINK = 1
|
||||
|
||||
# PlayStation 2
|
||||
else ifeq ($(platform), ps2)
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).a
|
||||
CC = mips64r5900el-ps2-elf-gcc$(EXE_EXT)
|
||||
CXX = mips64r5900el-ps2-elf-g++$(EXE_EXT)
|
||||
AR = mips64r5900el-ps2-elf-ar$(EXE_EXT)
|
||||
CFLAGS += -Wall -DPS2 -DABGR1555
|
||||
STATIC_LINKING = 1
|
||||
STATIC_LINKING_LINK = 1
|
||||
|
||||
# Windows
|
||||
else
|
||||
EXT ?= dll
|
||||
@@ -539,7 +529,9 @@ all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
@echo "** BUILDING $(TARGET) FOR PLATFORM $(platform) **"
|
||||
ifeq ($(STATIC_LINKING_LINK), 1)
|
||||
ifeq ($(platform), emscripten)
|
||||
$(CC) $(CFLAGS) $(OBJOUT)$@ $^
|
||||
else ifeq ($(STATIC_LINKING_LINK), 1)
|
||||
ifneq (,$(findstring msvc,$(platform)))
|
||||
$(LD) $(LINKOUT)$@ $(OBJECTS)
|
||||
else
|
||||
|
||||
@@ -5,7 +5,7 @@ COREDEFINES :=
|
||||
# my first make function!!!
|
||||
CHECK_ALL = $(strip $(foreach v,$(2),$(if $(findstring $(v),$(1)),$(v),)))
|
||||
|
||||
INCFLAGS := -I$(CORE_DIR)/../include -I$(LIBRETRO_COMM_DIR)/include
|
||||
INCFLAGS := -I$(LIBRETRO_COMM_DIR)/include
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
COREDEFINES += -DEMU_DEBUG
|
||||
@@ -109,7 +109,6 @@ COREDEFINES += $(EMU_DEFINES)
|
||||
|
||||
SOURCES_C := $(CORE_DIR)/libretro.c \
|
||||
$(CORE_DIR)/cursors.c \
|
||||
$(CORE_DIR)/miniz.c \
|
||||
$(EMU_SOURCES_C)
|
||||
SOURCES_CXX := $(EMU_SOURCES_CXX)
|
||||
SOURCES_ASM := $(EMU_SOURCES_ASM)
|
||||
@@ -124,6 +123,3 @@ ifneq ($(STATIC_LINKING), 1)
|
||||
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
||||
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
|
||||
endif
|
||||
|
||||
# Make sure C++ shares our include flags!
|
||||
CXXFLAGS += $(INCFLAGS)
|
||||
|
||||
@@ -53,8 +53,9 @@ SOEXT = .dll
|
||||
# Platform setup
|
||||
|
||||
STATIC_LINKING = 0
|
||||
platform = win
|
||||
PLATDEFS =
|
||||
PLATCFLAGS = -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 -DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCFLAGS = -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 -DWIN32 -DCORRECT_VRAM_READS -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCXXFLAGS = $(PLATCFLAGS)
|
||||
#PLATLDFLAGS = -shared -lm
|
||||
#PLATLDXFLAGS = -shared -lm
|
||||
@@ -81,17 +82,13 @@ LDXFLAGS = $(PLATLDXFLAGS) $(RETROLDXFLAGS)
|
||||
# Tuning
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
LDFLAGS += -DLL
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
LDFLAGS += -DLL
|
||||
endif
|
||||
|
||||
ifneq ($(LOG_PERFORMANCE),)
|
||||
|
||||
@@ -37,17 +37,10 @@ PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../IDE")
|
||||
INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/include")
|
||||
LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS80COMNTOOLS)../../VC/lib")
|
||||
|
||||
WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\MicrosoftSDK\InstalledSDKs\8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3" -v "Install Dir" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir := $(INETSDK)
|
||||
|
||||
WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include")
|
||||
WindowsSDKAtlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\atl")
|
||||
WindowsSDKCrtIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\crt")
|
||||
WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl")
|
||||
WindowsSDKMfcIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\mfc")
|
||||
WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib")
|
||||
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKAtlIncludeDir);$(WindowsSDKCrtIncludeDir);$(WindowsSDKGlIncludeDir);$(WindowsSDKMfcIncludeDir);libretro-common/include/compat/msvc
|
||||
export LIB := $(LIB);$(WindowsSDKLibDir)
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSdkDir)/Include;libretro/msvc/msvc-2005
|
||||
export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib
|
||||
|
||||
############
|
||||
# Extensions
|
||||
@@ -59,8 +52,9 @@ SOEXT = .dll
|
||||
# Platform setup
|
||||
|
||||
STATIC_LINKING = 0
|
||||
platform = win
|
||||
PLATDEFS =
|
||||
PLATCFLAGS = -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 -DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCFLAGS = -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 -DWIN32 -DCORRECT_VRAM_READS -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCXXFLAGS = $(PLATCFLAGS)
|
||||
#PLATLDFLAGS = -shared -lm
|
||||
#PLATLDXFLAGS = -shared -lm
|
||||
@@ -87,17 +81,13 @@ LDXFLAGS = $(PLATLDXFLAGS) $(RETROLDXFLAGS)
|
||||
# Tuning
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
LDFLAGS += -DLL
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
LDFLAGS += -DLL
|
||||
endif
|
||||
|
||||
ifneq ($(LOG_PERFORMANCE),)
|
||||
|
||||
@@ -52,8 +52,9 @@ SOEXT = .dll
|
||||
# Platform setup
|
||||
|
||||
STATIC_LINKING = 0
|
||||
platform = win
|
||||
PLATDEFS =
|
||||
PLATCFLAGS = -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 -DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCFLAGS = -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 -DWIN32 -DCORRECT_VRAM_READS -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCXXFLAGS = $(PLATCFLAGS)
|
||||
#PLATLDFLAGS = -shared -lm
|
||||
#PLATLDXFLAGS = -shared -lm
|
||||
@@ -80,17 +81,13 @@ LDXFLAGS = $(PLATLDXFLAGS) $(RETROLDXFLAGS)
|
||||
# Tuning
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
LDFLAGS += -DLL
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
LDFLAGS += -DLL
|
||||
endif
|
||||
|
||||
ifneq ($(LOG_PERFORMANCE),)
|
||||
|
||||
@@ -37,16 +37,11 @@ PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE")
|
||||
INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include")
|
||||
LIB := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/lib/amd64")
|
||||
|
||||
WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
|
||||
WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include")
|
||||
WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl")
|
||||
WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\x64")
|
||||
|
||||
INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)"
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKGlIncludeDir)
|
||||
export LIB := $(LIB);$(WindowsSDKLibDir)
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSdkDir)Include
|
||||
export LIB := $(LIB);$(WindowsSdkDir)Lib/x64
|
||||
|
||||
############
|
||||
# Extensions
|
||||
@@ -58,8 +53,9 @@ SOEXT = .dll
|
||||
# Platform setup
|
||||
|
||||
STATIC_LINKING = 0
|
||||
platform = win
|
||||
PLATDEFS =
|
||||
PLATCFLAGS = -DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCFLAGS = -DWIN32 -DCORRECT_VRAM_READS -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCXXFLAGS = $(PLATCFLAGS)
|
||||
#PLATLDFLAGS = -shared -lm
|
||||
#PLATLDXFLAGS = -shared -lm
|
||||
@@ -86,17 +82,13 @@ LDXFLAGS = $(PLATLDXFLAGS) $(RETROLDXFLAGS)
|
||||
# Tuning
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
LDFLAGS += -DLL
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
LDFLAGS += -DLL
|
||||
endif
|
||||
|
||||
ifneq ($(LOG_PERFORMANCE),)
|
||||
|
||||
@@ -37,16 +37,11 @@ PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE")
|
||||
INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include")
|
||||
LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS100COMNTOOLS)../../VC/lib")
|
||||
|
||||
WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')
|
||||
|
||||
WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include")
|
||||
WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl")
|
||||
WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib")
|
||||
|
||||
INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)"
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKGlIncludeDir)
|
||||
export LIB := $(LIB);$(WindowsSDKLibDir)
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSdkDir)Include
|
||||
export LIB := $(LIB);$(WindowsSdkDir)Lib
|
||||
|
||||
############
|
||||
# Extensions
|
||||
@@ -58,8 +53,9 @@ SOEXT = .dll
|
||||
# Platform setup
|
||||
|
||||
STATIC_LINKING = 0
|
||||
platform = win
|
||||
PLATDEFS =
|
||||
PLATCFLAGS = -DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCFLAGS = -DWIN32 -DCORRECT_VRAM_READS -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCXXFLAGS = $(PLATCFLAGS)
|
||||
#PLATLDFLAGS = -shared -lm
|
||||
#PLATLDXFLAGS = -shared -lm
|
||||
@@ -86,17 +82,13 @@ LDXFLAGS = $(PLATLDXFLAGS) $(RETROLDXFLAGS)
|
||||
# Tuning
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
LDFLAGS += -DLL
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
LDFLAGS += -DLL
|
||||
endif
|
||||
|
||||
ifneq ($(LOG_PERFORMANCE),)
|
||||
|
||||
@@ -61,8 +61,9 @@ SOEXT = .dll
|
||||
# Platform setup
|
||||
|
||||
STATIC_LINKING = 0
|
||||
platform = win
|
||||
PLATDEFS =
|
||||
PLATCFLAGS = -DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCFLAGS = -DWIN32 -DCORRECT_VRAM_READS -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DMSVC2010_EXPORTS -DFRONTEND_SUPPORTS_RGB565 -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
PLATCXXFLAGS = $(PLATCFLAGS)
|
||||
#PLATLDFLAGS = -shared -lm
|
||||
#PLATLDXFLAGS = -shared -lm
|
||||
@@ -89,17 +90,13 @@ LDXFLAGS = $(PLATLDXFLAGS) $(RETROLDXFLAGS)
|
||||
# Tuning
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
CFLAGS += -Od -Zi -D_DEBUG
|
||||
CXXFLAGS += -Od -Zi -D_DEBUG
|
||||
LDFLAGS += -DEBUG -DLL
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
LDFLAGS += -DLL
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
LDFLAGS += -DLL
|
||||
endif
|
||||
|
||||
ifneq ($(LOG_PERFORMANCE),)
|
||||
|
||||
@@ -69,7 +69,7 @@ extern "C" {
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__PS3__)
|
||||
# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__CELLOS_LV2__)
|
||||
# define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
|
||||
# else
|
||||
# define RETRO_API RETRO_CALLCONV
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__PS3__) || defined(PSP) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
|
||||
#if defined(__CELLOS_LV2__) || defined(PSP) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
|
||||
/* No mman available */
|
||||
#elif defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__PS3__)
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <sys/fs_external.h>
|
||||
#endif
|
||||
|
||||
@@ -75,8 +75,8 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
}
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(__PS3__)
|
||||
#define PATH_MAX_LENGTH 1024
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
|
||||
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(GEKKO)|| defined(WIIU)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
#else
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __PS3__
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/cell_fs.h>
|
||||
#define O_RDONLY CELL_FS_O_RDONLY
|
||||
#define O_WRONLY CELL_FS_O_WRONLY
|
||||
@@ -123,7 +123,7 @@ int64_t retro_vfs_file_seek_internal(libretro_vfs_implementation_file *stream, i
|
||||
/* VC2005 and up have a special 64-bit fseek */
|
||||
#ifdef ATLEAST_VC2005
|
||||
return _fseeki64(stream->fp, offset, whence);
|
||||
#elif defined(__PS3__) || defined(_MSC_VER) && _MSC_VER <= 1310
|
||||
#elif defined(__CELLOS_LV2__) || defined(_MSC_VER) && _MSC_VER <= 1310
|
||||
return fseek(stream->fp, (long)offset, whence);
|
||||
#else
|
||||
return fseeko(stream->fp, (off_t)offset, whence);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
||||
Copyright 2013-2014 RAD Game Tools and Valve Software
|
||||
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
|
||||
|
||||
All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,28 +1,21 @@
|
||||
# Software Information
|
||||
display_name = "Palm OS (Mu)"
|
||||
authors = "guicrith / meepingsnesroms; Stephanie Gawroriski (Xer Shadow Tail)"
|
||||
supported_extensions = "prc|pqa|img|pdb|zip"
|
||||
authors = "guicrith / meepingsnesroms"
|
||||
supported_extensions = "prc|pqa|img"
|
||||
corename = "Mu"
|
||||
license = "CC BY-NC 3.0 US (Non-commercial)"
|
||||
permissions = ""
|
||||
display_version = "v1.3.1"
|
||||
categories = "Emulator"
|
||||
|
||||
# Hardware Information
|
||||
manufacturer = "Palm"
|
||||
categories = "Emulator"
|
||||
systemname = "Palm OS"
|
||||
|
||||
# Libretro Features
|
||||
license = "Non-commercial"
|
||||
permissions = ""
|
||||
display_version = "v1.1.0"
|
||||
supports_no_game = "true"
|
||||
|
||||
# BIOS/Firmware
|
||||
firmware_count = 5
|
||||
firmware0_desc = "palmos40-en-m500.rom (Palm OS 4.0)"
|
||||
firmware0_path = "palmos40-en-m500.rom"
|
||||
firmware0_opt = "true"
|
||||
firmware1_desc = "palmos41-en-m515.rom (Palm OS 4.1)"
|
||||
firmware1_path = "palmos41-en-m515.rom"
|
||||
firmware1_opt = "false"
|
||||
firmware1_opt = "true"
|
||||
firmware2_desc = "palmos52-en-t3.rom (Palm OS 5.2.1)"
|
||||
firmware2_path = "palmos52-en-t3.rom"
|
||||
firmware2_opt = "true"
|
||||
@@ -32,5 +25,3 @@ firmware3_opt = "true"
|
||||
firmware4_desc = "bootloader-dbvz.rom (MC68VZ328 UART Bootloader)"
|
||||
firmware4_path = "bootloader-dbvz.rom"
|
||||
firmware4_opt = "true"
|
||||
|
||||
description = "An emulator for the Palm m515 OS ported to libretro. It is intended to avoid hacks like those used by the POSE emulator, where API calls are intercepted and replaced with those that don't use the actual hardware."
|
||||
@@ -1,14 +0,0 @@
|
||||
# Only include the sub-project if Qt was actually found
|
||||
find_package(Qt5 OPTIONAL_COMPONENTS Core Widgets)
|
||||
if(Qt5_FOUND EQUAL 0)
|
||||
message("Qt5 was not found by CMake, check readme.md!")
|
||||
endif()
|
||||
|
||||
# Was this actually found now?
|
||||
if(NOT Qt5_FOUND EQUAL 0)
|
||||
# Information!
|
||||
message("Found Qt5, so including the interface as an option.")
|
||||
|
||||
# Where the project really exists
|
||||
add_subdirectory(Mu)
|
||||
endif()
|
||||
@@ -1,81 +0,0 @@
|
||||
# We use these to automatically generate UI headers and otherwise in Qt
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
# We need all the Qt5 libraries
|
||||
find_package(Qt5 OPTIONAL_COMPONENTS Core Gui Widgets Multimedia Svg)
|
||||
|
||||
# Application Icon for Mu
|
||||
if(WIN32)
|
||||
set(MU_APP_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/windows/app.rc")
|
||||
else()
|
||||
set(MU_APP_RESOURCES)
|
||||
endif()
|
||||
|
||||
# Setup executable for running
|
||||
add_executable(QtMu
|
||||
debugviewer.cpp
|
||||
debugviewer.h
|
||||
debugviewer.ui
|
||||
emuwrapper.cpp
|
||||
emuwrapper.h
|
||||
main.cpp
|
||||
mainwindow.cpp
|
||||
mainwindow.h
|
||||
mainwindow.qrc
|
||||
mainwindow.ui
|
||||
settingsmanager.cpp
|
||||
settingsmanager.h
|
||||
settingsmanager.ui
|
||||
statemanager.cpp
|
||||
statemanager.ui
|
||||
touchscreen.h
|
||||
touchscreen.cpp
|
||||
${MU_APP_RESOURCES})
|
||||
|
||||
# The Qt build requires modern-ish C++11
|
||||
set_target_properties(QtMu PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS YES)
|
||||
|
||||
# Include the required includes
|
||||
target_include_directories(QtMu PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/include"
|
||||
|
||||
# When we auto-generate the UI code, we refer to includes that are in
|
||||
# the Qt source directory
|
||||
"${PROJECT_SOURCE_DIR}/qtBuildSystem/Mu")
|
||||
|
||||
# Used to indicate some things for compatibility
|
||||
add_definitions(-DBUILT_FROM_CMAKE)
|
||||
|
||||
# Annoying Visual Studio Warnings
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
# Needed for GCC
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Need to link into all these Qt components
|
||||
target_link_libraries(QtMu
|
||||
MuCore Threads::Threads
|
||||
Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Multimedia Qt5::Svg)
|
||||
|
||||
# Deployment for Windows
|
||||
if(WIN32)
|
||||
# Retrieve the absolute path to qmake and then use that path to find
|
||||
# the windeployqt executable
|
||||
get_target_property(QMAKE_EXE Qt5::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY)
|
||||
|
||||
find_program(WINDEPLOYQT_ENV_SETUP qtenv2.bat HINTS "${QT_BIN_DIR}")
|
||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_BIN_DIR}")
|
||||
|
||||
# Run windeployqt immediately after build
|
||||
add_custom_command(TARGET QtMu
|
||||
POST_BUILD
|
||||
COMMAND "${WINDEPLOYQT_ENV_SETUP}" && "${WINDEPLOYQT_EXECUTABLE}" \"$<TARGET_FILE:QtMu>\"
|
||||
)
|
||||
endif()
|
||||
@@ -38,7 +38,6 @@ windows{
|
||||
QMAKE_LFLAGS += -fopenmp
|
||||
DEFINES += EMU_MULTITHREADED EMU_MANAGE_HOST_CPU_PIPELINE
|
||||
}
|
||||
CONFIG += cpu_x86_32 # TODO:this should be auto detected in the future
|
||||
}
|
||||
|
||||
macx{
|
||||
@@ -46,7 +45,6 @@ macx{
|
||||
ICON = macos/Mu.icns
|
||||
QMAKE_INFO_PLIST = macos/Info.plist
|
||||
DEFINES += EMU_MULTITHREADED EMU_MANAGE_HOST_CPU_PIPELINE
|
||||
CONFIG += cpu_x86_64 # Mac OS is only x86_64
|
||||
}
|
||||
|
||||
linux-g++{
|
||||
@@ -54,7 +52,6 @@ linux-g++{
|
||||
QMAKE_CXXFLAGS += -fopenmp
|
||||
QMAKE_LFLAGS += -fopenmp
|
||||
DEFINES += EMU_MULTITHREADED EMU_MANAGE_HOST_CPU_PIPELINE
|
||||
CONFIG += cpu_x86_64 # TODO:this should be auto detected in the future
|
||||
}
|
||||
|
||||
android{
|
||||
@@ -62,7 +59,6 @@ android{
|
||||
QMAKE_CXXFLAGS += -fopenmp
|
||||
QMAKE_LFLAGS += -fopenmp
|
||||
DEFINES += EMU_MULTITHREADED EMU_MANAGE_HOST_CPU_PIPELINE
|
||||
CONFIG += cpu_armv7 # TODO:this should be auto detected in the future
|
||||
}
|
||||
|
||||
|
||||
@@ -85,133 +81,7 @@ EMU_NO_SAFETY{
|
||||
DEFINES += EMU_NO_SAFETY
|
||||
}
|
||||
|
||||
support_palm_os5{
|
||||
DEFINES += EMU_SUPPORT_PALM_OS5 # the Qt build will not be supporting anything too slow to run OS 5
|
||||
DEFINES += SUPPORT_LINUX # forces the dynarec to use accurate mode and disable Nspire OS hacks
|
||||
|
||||
EMU_NO_SAFETY{
|
||||
# Windows is only supported in 32 bit mode right now(this is a limitation of the dynarec)
|
||||
# iOS needs IS_IOS_BUILD set, but the Qt port does not support iOS currently
|
||||
|
||||
cpu_x86_32{
|
||||
SOURCES += \
|
||||
../../src/armv5te/translate_x86.c \
|
||||
../../src/armv5te/asmcode_x86.S
|
||||
}
|
||||
else{
|
||||
# x86 has this implemented in asmcode_x86.S
|
||||
SOURCES += \
|
||||
../../src/armv5te/asmcode.c
|
||||
}
|
||||
|
||||
cpu_x86_64{
|
||||
SOURCES += \
|
||||
../../src/armv5te/translate_x86_64.c \
|
||||
../../src/armv5te/asmcode_x86_64.S
|
||||
}
|
||||
|
||||
cpu_armv7{
|
||||
SOURCES += \
|
||||
../../src/armv5te/translate_arm.cpp \
|
||||
../../src/armv5te/asmcode_arm.S
|
||||
}
|
||||
|
||||
cpu_armv8{
|
||||
SOURCES += \
|
||||
../../src/armv5te/translate_aarch64.cpp \
|
||||
../../src/armv5te/asmcode_aarch64.S
|
||||
}
|
||||
}
|
||||
else{
|
||||
# use platform independant C with no dynarec
|
||||
SOURCES += \
|
||||
../../src/armv5te/asmcode.c \
|
||||
../../src/armv5te/uArm/CPU_2.c \
|
||||
../../src/armv5te/uArm/icache.c \
|
||||
../../src/armv5te/uArm/uArmGlue.cpp
|
||||
DEFINES += NO_TRANSLATION
|
||||
}
|
||||
|
||||
windows{
|
||||
SOURCES += \
|
||||
../../src/armv5te/os/os-win32.c
|
||||
}
|
||||
|
||||
macx|linux-g++|android{
|
||||
SOURCES += \
|
||||
../../src/armv5te/os/os-linux.c
|
||||
}
|
||||
|
||||
SOURCES += \
|
||||
../../src/pxa260/pxa260_DMA.c \
|
||||
../../src/pxa260/pxa260_DSP.c \
|
||||
../../src/pxa260/pxa260_GPIO.c \
|
||||
../../src/pxa260/pxa260_IC.c \
|
||||
../../src/pxa260/pxa260_LCD.c \
|
||||
../../src/pxa260/pxa260_PwrClk.c \
|
||||
../../src/pxa260/pxa260_RTC.c \
|
||||
../../src/pxa260/pxa260_TIMR.c \
|
||||
../../src/pxa260/pxa260_UART.c \
|
||||
../../src/pxa260/pxa260I2c.c \
|
||||
../../src/pxa260/pxa260Memctrl.c \
|
||||
../../src/pxa260/pxa260Timing.c \
|
||||
../../src/pxa260/pxa260Ssp.c \
|
||||
../../src/pxa260/pxa260Udc.c \
|
||||
../../src/pxa260/pxa260.c \
|
||||
../../src/armv5te/arm_interpreter.cpp \
|
||||
../../src/armv5te/cpu.cpp \
|
||||
../../src/armv5te/coproc.cpp \
|
||||
../../src/armv5te/disasm.c \
|
||||
../../src/armv5te/emuVarPool.c \
|
||||
../../src/armv5te/thumb_interpreter.cpp \
|
||||
../../src/armv5te/mem.c \
|
||||
../../src/armv5te/mmu.c \
|
||||
../../src/tps65010.c \
|
||||
../../src/tsc2101.c \
|
||||
../../src/w86l488.c
|
||||
|
||||
HEADERS += \
|
||||
../../src/pxa260/pxa260_CPU.h \
|
||||
../../src/pxa260/pxa260_DMA.h \
|
||||
../../src/pxa260/pxa260_DSP.h \
|
||||
../../src/pxa260/pxa260_GPIO.h \
|
||||
../../src/pxa260/pxa260_IC.h \
|
||||
../../src/pxa260/pxa260_LCD.h \
|
||||
../../src/pxa260/pxa260_PwrClk.h \
|
||||
../../src/pxa260/pxa260_RTC.h \
|
||||
../../src/pxa260/pxa260_TIMR.h \
|
||||
../../src/pxa260/pxa260_UART.h \
|
||||
../../src/pxa260/pxa260I2c.h \
|
||||
../../src/pxa260/pxa260Memctrl.h \
|
||||
../../src/pxa260/pxa260Timing.h \
|
||||
../../src/pxa260/pxa260Ssp.h \
|
||||
../../src/pxa260/pxa260Udc.h \
|
||||
../../src/pxa260/pxa260_types.h \
|
||||
../../src/pxa260/pxa260_math64.h \
|
||||
../../src/pxa260/pxa260Accessors.c.h \
|
||||
../../src/pxa260/pxa260.h \
|
||||
../../src/armv5te/os/os.h \
|
||||
../../src/armv5te/uArm/CPU_2.h \
|
||||
../../src/armv5te/uArm/icache.h \
|
||||
../../src/armv5te/uArm/uArmGlue.h \
|
||||
../../src/armv5te/asmcode.h \
|
||||
../../src/armv5te/bitfield.h \
|
||||
../../src/armv5te/cpu.h \
|
||||
../../src/armv5te/disasm.h \
|
||||
../../src/armv5te/emu.h \
|
||||
../../src/armv5te/mem.h \
|
||||
../../src/armv5te/translate.h \
|
||||
../../src/armv5te/cpudefs.h \
|
||||
../../src/armv5te/debug.h \
|
||||
../../src/armv5te/mmu.h \
|
||||
../../src/armv5te/armsnippets.h \
|
||||
../../src/armv5te/literalpool.h \
|
||||
../../src/tungstenT3Bus.h \
|
||||
../../src/tps65010.h \
|
||||
../../src/tsc2101.h \
|
||||
../../src/w86l488.h
|
||||
}
|
||||
|
||||
DEFINES += EMU_SUPPORT_PALM_OS5 # the Qt build will not be supporting anything too slow to run OS 5
|
||||
CONFIG += c++11
|
||||
|
||||
INCLUDEPATH += $$PWD/qt-common/include
|
||||
@@ -221,7 +91,6 @@ SOURCES += \
|
||||
../../src/audio/blip_buf.c \
|
||||
../../src/dbvz.c \
|
||||
../../src/emulator.c \
|
||||
../../src/serial.c \
|
||||
../../src/fileLauncher/launcher.c \
|
||||
../../src/flx68000.c \
|
||||
../../src/m5XXBus.c \
|
||||
@@ -232,9 +101,32 @@ SOURCES += \
|
||||
../../src/m68k/m68kopnz.c \
|
||||
../../src/m68k/m68kops.c \
|
||||
../../src/pdiUsbD12.c \
|
||||
../../src/pxa260/disasm.c \
|
||||
../../src/pxa260/pxa260.c \
|
||||
../../src/pxa260/pxa260I2c.c \
|
||||
../../src/pxa260/pxa260Memctrl.c \
|
||||
../../src/pxa260/pxa260Ssp.c \
|
||||
../../src/pxa260/pxa260Timing.c \
|
||||
../../src/pxa260/pxa260Udc.c \
|
||||
../../src/pxa260/pxa260_CPU.c \
|
||||
../../src/pxa260/pxa260_DMA.c \
|
||||
../../src/pxa260/pxa260_DSP.c \
|
||||
../../src/pxa260/pxa260_GPIO.c \
|
||||
../../src/pxa260/pxa260_IC.c \
|
||||
../../src/pxa260/pxa260_LCD.c \
|
||||
../../src/pxa260/pxa260_MMU.c \
|
||||
../../src/pxa260/pxa260_PwrClk.c \
|
||||
../../src/pxa260/pxa260_RTC.c \
|
||||
../../src/pxa260/pxa260_TIMR.c \
|
||||
../../src/pxa260/pxa260_UART.c \
|
||||
../../src/pxa260/pxa260_cp15.c \
|
||||
../../src/pxa260/pxa260_icache.c \
|
||||
../../src/sdCard.c \
|
||||
../../src/sed1376.c \
|
||||
../../src/silkscreen.c \
|
||||
../../src/tps65010.c \
|
||||
../../src/tsc2101.c \
|
||||
../../src/w86l488.c \
|
||||
debugviewer.cpp \
|
||||
emuwrapper.cpp \
|
||||
main.cpp \
|
||||
@@ -262,6 +154,29 @@ HEADERS += \
|
||||
../../src/pdiUsbD12.h \
|
||||
../../src/pdiUsbD12CommandNames.c.h \
|
||||
../../src/portability.h \
|
||||
../../src/pxa260/disasm.h \
|
||||
../../src/pxa260/pxa260.h \
|
||||
../../src/pxa260/pxa260Accessors.c.h \
|
||||
../../src/pxa260/pxa260I2c.h \
|
||||
../../src/pxa260/pxa260Memctrl.h \
|
||||
../../src/pxa260/pxa260Ssp.h \
|
||||
../../src/pxa260/pxa260Timing.h \
|
||||
../../src/pxa260/pxa260Udc.h \
|
||||
../../src/pxa260/pxa260_CPU.h \
|
||||
../../src/pxa260/pxa260_DMA.h \
|
||||
../../src/pxa260/pxa260_DSP.h \
|
||||
../../src/pxa260/pxa260_GPIO.h \
|
||||
../../src/pxa260/pxa260_IC.h \
|
||||
../../src/pxa260/pxa260_LCD.h \
|
||||
../../src/pxa260/pxa260_MMU.h \
|
||||
../../src/pxa260/pxa260_PwrClk.h \
|
||||
../../src/pxa260/pxa260_RTC.h \
|
||||
../../src/pxa260/pxa260_TIMR.h \
|
||||
../../src/pxa260/pxa260_UART.h \
|
||||
../../src/pxa260/pxa260_cp15.h \
|
||||
../../src/pxa260/pxa260_icache.h \
|
||||
../../src/pxa260/pxa260_math64.h \
|
||||
../../src/pxa260/pxa260_types.h \
|
||||
../../src/sdCard.h \
|
||||
../../src/sdCardAccessors.c.h \
|
||||
../../src/sdCardCommandNames.c.h \
|
||||
@@ -270,6 +185,10 @@ HEADERS += \
|
||||
../../src/sed1376Accessors.c.h \
|
||||
../../src/sed1376RegisterNames.c.h \
|
||||
../../src/silkscreen.h \
|
||||
../../src/tps65010.h \
|
||||
../../src/tsc2101.h \
|
||||
../../src/tungstenT3Bus.h \
|
||||
../../src/w86l488.h \
|
||||
debugviewer.h \
|
||||
emuwrapper.h \
|
||||
mainwindow.h \
|
||||
|
||||
@@ -17,6 +17,7 @@ DebugViewer::DebugViewer(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::DebugViewer){
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
bitsPerEntry = 8;
|
||||
debugRadioButtonHandler();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,11 +9,7 @@
|
||||
#include <atomic>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(BUILT_FROM_CMAKE)
|
||||
#include "emulator.h"
|
||||
#else
|
||||
#include "../../include/emulator.h"
|
||||
#endif
|
||||
#include "../../src/emulator.h"
|
||||
|
||||
class EmuWrapper{
|
||||
private:
|
||||
@@ -54,9 +50,7 @@ public:
|
||||
EmuWrapper();
|
||||
~EmuWrapper();
|
||||
|
||||
uint32_t init(const QString &assetPath, const QString &osVersion,
|
||||
bool syncRtc = false, bool allowInvalidBehavior = false,
|
||||
bool fastBoot = false, const QString &serialPortDev = "");
|
||||
uint32_t init(const QString& assetPath, const QString& osVersion, bool syncRtc = false, bool allowInvalidBehavior = false, bool fastBoot = false);
|
||||
void exit();
|
||||
void pause();
|
||||
void resume();
|
||||
|
||||
@@ -47,7 +47,6 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||
stateManager = new StateManager(this);
|
||||
emuDebugger = new DebugViewer(this);
|
||||
refreshDisplay = new QTimer(this);
|
||||
|
||||
audioDevice = new QAudioOutput(format, this);
|
||||
audioOut = audioDevice->start();
|
||||
|
||||
@@ -227,10 +226,7 @@ void MainWindow::updateDisplay(){
|
||||
ui->display->repaint();
|
||||
|
||||
//audio
|
||||
if (audioOut != NULL) {
|
||||
audioOut->write((const char*)emu.getAudioSamples(),
|
||||
AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
|
||||
}
|
||||
audioOut->write((const char*)emu.getAudioSamples(), AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
|
||||
|
||||
//power LED
|
||||
ui->powerButtonLed->setStyleSheet(emu.getPowerButtonLed() ? "background: lime" : "");
|
||||
@@ -333,14 +329,7 @@ void MainWindow::on_center_released(){
|
||||
void MainWindow::on_ctrlBtn_clicked(){
|
||||
if(!emu.isInited()){
|
||||
QString sysDir = settings->value("resourceDirectory", "").toString();
|
||||
uint32_t error = emu.init(
|
||||
sysDir,
|
||||
settings->value("palmOsVersionString", "Palm m515/Palm OS 4.1")
|
||||
.toString(),
|
||||
settings->value("featureSyncedRtc", false).toBool(),
|
||||
settings->value("featureDurable", false).toBool(),
|
||||
settings->value("fastBoot", false).toBool(),
|
||||
settings->value("serialPortDev", "").toString());
|
||||
uint32_t error = emu.init(sysDir, settings->value("palmOsVersionString", "Palm m515/Palm OS 4.1").toString(), settings->value("featureSyncedRtc", false).toBool(), settings->value("featureDurable", false).toBool(), settings->value("fastBoot", false).toBool());
|
||||
|
||||
if(error == EMU_ERROR_NONE){
|
||||
emu.setCpuSpeed(settings->value("cpuSpeed", 1.00).toDouble());
|
||||
|
||||
@@ -19,6 +19,7 @@ SettingsManager::SettingsManager(QWidget* parent) :
|
||||
|
||||
//init GUI
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
//set all GUI items to current config values
|
||||
ui->homeDirectory->setText(settings->value("resourceDirectory", "").toString());
|
||||
@@ -31,10 +32,6 @@ SettingsManager::SettingsManager(QWidget* parent) :
|
||||
ui->featureSyncedRtc->setChecked(settings->value("featureSyncedRtc", false).toBool());
|
||||
ui->featureDurable->setChecked(settings->value("featureDurable", false).toBool());
|
||||
|
||||
ui->serialPortDev->setText(settings->value("serialPortDev",
|
||||
"").toString());
|
||||
connect(ui->serialPortDev, &QLineEdit::textChanged, this, &SettingsManager::on_serialPortDev_textChanged);
|
||||
|
||||
setKeySelectorState(-1);
|
||||
updateButtonKeys();
|
||||
}
|
||||
@@ -170,7 +167,3 @@ void SettingsManager::on_palmOsVersion_currentIndexChanged(int index){
|
||||
settings->setValue("palmOsVersionIndex", index);
|
||||
settings->setValue("palmOsVersionString", ui->palmOsVersion->itemText(index));
|
||||
}
|
||||
|
||||
void SettingsManager::on_serialPortDev_textChanged(const QString& arg1) {
|
||||
settings->setValue("serialPortDev", ui->serialPortDev->text());
|
||||
}
|
||||
|
||||
@@ -51,8 +51,6 @@ private slots:
|
||||
void on_cpuSpeed_valueChanged(double arg1);
|
||||
void on_palmOsVersion_currentIndexChanged(int index);
|
||||
|
||||
void on_serialPortDev_textChanged(const QString& arg1);
|
||||
|
||||
private:
|
||||
Ui::SettingsManager* ui;
|
||||
QSettings* settings;
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-284</y>
|
||||
<y>0</y>
|
||||
<width>613</width>
|
||||
<height>705</height>
|
||||
<height>444</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
@@ -430,16 +430,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="serialPortDevLabel">
|
||||
<property name="text">
|
||||
<string>Serial Port Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="serialPortDev"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -21,6 +21,7 @@ StateManager::StateManager(QWidget* parent) :
|
||||
|
||||
//init GUI
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
//this allows resizing the screenshot of the savestate
|
||||
this->installEventFilter(this);
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,3,0,0
|
||||
PRODUCTVERSION 1,3,0,0
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Mu\0"
|
||||
VALUE "FileDescription", "Non-commercial Palm OS emulator.\0"
|
||||
VALUE "FileVersion", "1.3\0"
|
||||
VALUE "InternalName", "Mu\0"
|
||||
VALUE "LegalCopyright", "CC BY-NC 3.0 US: Emily (meepingsnesroms), Stephanie Gawroriski\0"
|
||||
VALUE "LegalTrademarks1", "CC BY-NC 3.0 US: Emily (meepingsnesroms), Stephanie Gawroriski\0"
|
||||
VALUE "LegalTrademarks2", "CC BY-NC 3.0 US: Emily (meepingsnesroms), Stephanie Gawroriski\0"
|
||||
VALUE "OriginalFilename", "QtMu.exe\0"
|
||||
VALUE "ProductName", "Mu\0"
|
||||
VALUE "ProductVersion", "1.3\0"
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
||||
|
||||
id ICON "Mu.ico"
|
||||
82
readme.md
82
readme.md
@@ -1,33 +1,27 @@
|
||||
# Mu, a Palm OS Emulator
|
||||
# Palm OS emulator(Mu)
|
||||
|
||||
The continuation of the Mu along with the RetroArch Core is dedicated to
|
||||
Emily (1998-2020), your friendship was very important to me and I hope
|
||||
that you are resting well.
|
||||
-- Your friend, Stephanie
|
||||
This is a complete restart of my Palm OS emulator, with the last one the code got too messy and the goal too ambitious(to emulate every Palm API in software and for compatibility with all Palm OS versions and devices).
|
||||
|
||||
# The goal of this project
|
||||
|
||||
This is a complete restart of my Palm OS emulator, with the last one the code got too messy and the goal too ambitious(to emulate every palm API in software and for compatibility with all Palm OS versions and devices).
|
||||
|
||||
To emulate every part of the Palm m515 that is used by the OS perfectly.
|
||||
This means no hacks like POSE where API calls are intercepted and replaced with those that dont use the actual hardware.
|
||||
To emulate every part of the Palm m515 and Tungsten T3 that is used by the OS perfectly.
|
||||
This means no hacks like POSE where API calls are intercepted and replaced with those that don't use the actual hardware.
|
||||
It is also written in C for RetroArch so it will run on everything at the start, not just Win95 like POSE and Copilot and is being developed with modern emulator features in mind, save/load state and overclocking are available from the start.
|
||||
|
||||
## Why the m515?
|
||||
|
||||
It is the best Palm brand OS 4 device that has no special hardware builtin(cellphone, barcode scanner, keyboard attachment), it has a color screen, and available ROM dumps.
|
||||
It is the best Palm brand OS 4 device that has no special hardware built-in(cellphone, barcode scanner, keyboard attachment), it has a color screen, and available ROM dumps.
|
||||
|
||||
## Why the Tungsten T3
|
||||
|
||||
It has the best resolution and a well documented CPU.
|
||||
|
||||
## What about accessories?
|
||||
|
||||
The Palm keyboard attachment will likely be emulated later on so the PC keyboard can be used on text fields.
|
||||
|
||||
## What about OS 5?
|
||||
|
||||
I am planning on adding Tungsten T3 support as soon as possible.
|
||||
|
||||
## Credits
|
||||
[Firebird Emu](https://github.com/nspire-emus/firebird) (ARMv5TE Core)
|
||||
[uARM](https://dmitry.gr/?r=05.Projects&proj=07.%20Linux%20on%208bit) (PXA260 CPU Peripherals and reference CPU core)
|
||||
[uARM](https://dmitry.gr/?r=05.Projects&proj=07.%20Linux%20on%208bit) (Most of the PXA260 CPU)
|
||||
[Musashi v3.4](https://github.com/kstenerud/Musashi) (last version that builds outside of MAME)(68k Core)
|
||||
[blip_buf 1.1.0](https://github.com/TASVideos/BizHawk/tree/master/blip_buf) (Audio Resampler)
|
||||
https://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/App-palm-icon.html (Desktop Icon)
|
||||
@@ -37,49 +31,21 @@ https://www.flaticon.com/free-icon/cow_235371#term=cow&page=1&position=13 (muExp
|
||||
https://findicons.com/icon/164302/cursor (Libretro Port Joystick Cursor)
|
||||
|
||||
## Building
|
||||
|
||||
#### Using CMake
|
||||
|
||||
Using CMake, you just need to do:
|
||||
|
||||
* `cmake .`
|
||||
* `cmake --build .`
|
||||
* You may specify a CMake target.
|
||||
|
||||
#### For RetroArch
|
||||
|
||||
Make sure you have done all the steps here https://docs.libretro.com/ under "For Developers/Compilation" so you build environment works.
|
||||
|
||||
cd ./libretroBuildSystem
|
||||
make
|
||||
|
||||
To load multiple files at once, place PRCs and PDBs into a ZIP file and then
|
||||
load that ZIP file. PDBs will be installed first followed by PRC files.
|
||||
|
||||
#### For Qt
|
||||
Install Qt 5.11.1 and Qt Creator(optional) if not installed
|
||||
Open the .pro file in Qt Creator and click "Run" or build from command line
|
||||
|
||||
First install _Qt 5.14.2_, you may optional install as well _Qt Creator_.
|
||||
##### To build without Qt Creator(untested)
|
||||
|
||||
* Windows: <https://download.qt.io/archive/qt/5.14/5.14.2/qt-opensource-windows-x86-5.14.2.exe>
|
||||
* Mac: <https://download.qt.io/archive/qt/5.14/5.14.2/qt-opensource-mac-x64-5.14.2.dmg>
|
||||
* Linux: <https://download.qt.io/archive/qt/5.14/5.14.2/qt-opensource-linux-x64-5.14.2.run>
|
||||
|
||||
When running _CMake_ you will need to pass `-DCMAKE_PREFIX_PATH` to the
|
||||
location of `Qt5Config.cmake`.
|
||||
|
||||
* With _Qt 5.14.2_ on Windows building with...
|
||||
* mingw-w64: `C:\qt\Qt5.14.2\5.14.2\mingw73_64\lib\cmake\Qt5`
|
||||
* Visual Studio: `C:\qt\Qt5.14.2\5.14.2\msvc2017_64\lib\cmake\Qt5`
|
||||
|
||||
If you are using CLion, you may need to go into _Settings_ ->
|
||||
_Build, Execution, Deployment_ -> _CMake_ and add it to _CMake Options_.
|
||||
|
||||
For Qt Creator, open the `.pro` file and click "Run" or build from
|
||||
command line.
|
||||
|
||||
If you get `error: 'thread' in namespace 'std' does not name a type` while
|
||||
trying to build the Qt Project then you should install the _POSIX Threaded_
|
||||
variant of Mingw-w64 and not the _Win32 Threaded_ variant.
|
||||
cd ./qtBuildSystem/Mu
|
||||
qmake
|
||||
make
|
||||
|
||||
#### TestSuite for Palm OS
|
||||
Install prc-tools from the below link(self compiled or prepackaged VM)
|
||||
@@ -87,12 +53,6 @@ Install prc-tools from the below link(self compiled or prepackaged VM)
|
||||
cd ./tools/palm/hwTestSuite
|
||||
./make.sh
|
||||
|
||||
#### MuExpDriver for Palm OS
|
||||
Install prc-tools from the below link(self compiled or prepackaged VM)
|
||||
|
||||
cd ./tools/palm/muExpansionDriver
|
||||
./make.sh
|
||||
|
||||
## Running
|
||||
#### Files
|
||||
palmos40-en-m500.rom: f50e4d5e4d98dc831f2c34a9107651eb (MD5)
|
||||
@@ -106,7 +66,7 @@ bootloader-dbvz.rom: 9da101cd2317830649a31f8fa46debec (MD5)
|
||||
3. (Optional)Copy "bootloader-en-m515.rom" to "~/Mu"
|
||||
4. Run emu and press start button
|
||||
|
||||
#### For RetroArch
|
||||
#### For RetroArch
|
||||
1. Download "Palm OS(Mu)" from "Online Updater->Core Updater"
|
||||
2. Go back, select "Load Core", select "Palm OS(Mu)"
|
||||
3. Copy "palmos41-en-m515.rom" and "palmos52-en-t3.rom" to the RetroArch system directory
|
||||
@@ -117,12 +77,6 @@ bootloader-dbvz.rom: 9da101cd2317830649a31f8fa46debec (MD5)
|
||||
[Prc-tools, Palm OS SDKs, pilrc, pilot-link](https://github.com/meepingsnesroms/prc-tools-remix)
|
||||
|
||||
## License
|
||||
|
||||
* `CC BY-NC 3.0 US`
|
||||
* Attribution is to:
|
||||
* Emily "meepingsnesroms"
|
||||
* Stephanie Gawroriski <xerthesquirrel@gmail.com>
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc/3.0/us/">Creative Commons Attribution-NonCommercial 3.0 United States License</a>.
|
||||
|
||||
## Links
|
||||
@@ -130,4 +84,4 @@ bootloader-dbvz.rom: 9da101cd2317830649a31f8fa46debec (MD5)
|
||||
[Discord](https://discord.gg/hWSz8VN)
|
||||
|
||||
## Also see Mu's sister project
|
||||
[🐿SquirrelJME](https://squirreljme.cc/)
|
||||
[🐿SquirrelJME](https://multiphasicapps.net)
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# Base Mu library
|
||||
add_library(MuCore STATIC
|
||||
ads7846.c
|
||||
dbvz.c
|
||||
emulator.c
|
||||
serial.c
|
||||
flx68000.c
|
||||
m5XXBus.c
|
||||
pdiUsbD12.c
|
||||
sdCard.c
|
||||
sed1376.c
|
||||
silkscreen.c
|
||||
tps65010.c
|
||||
tsc2101.c
|
||||
w86l488.c)
|
||||
|
||||
# Make this position independent so it can be linked into shared libraries
|
||||
set_property(TARGET MuCore
|
||||
PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Bring all the sub-modules as needed
|
||||
target_link_libraries(MuCore
|
||||
MuCorePxa260Experimental
|
||||
MuCoreFileLauncher
|
||||
MuCoreAudio
|
||||
MuCoreM68k)
|
||||
|
||||
# Includes for the project
|
||||
target_include_directories(MuCore PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
# Core Mu
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(fileLauncher)
|
||||
|
||||
# Classic m68k Core
|
||||
add_subdirectory(m68k)
|
||||
|
||||
# Experimental ARM Cores
|
||||
add_subdirectory(armv5te)
|
||||
add_subdirectory(pxa260)
|
||||
@@ -1,68 +0,0 @@
|
||||
# Experimental ARM V5TE Module
|
||||
add_library(MuCoreArmV5TEExperimental STATIC
|
||||
uArm/CPU_2.c
|
||||
uArm/icache.c
|
||||
uArm/uArmGlue.cpp
|
||||
arm_interpreter.cpp
|
||||
asmcode.c
|
||||
coproc.cpp
|
||||
cpu.cpp
|
||||
disasm.c
|
||||
emuVarPool.c
|
||||
mem.c
|
||||
mmu.c
|
||||
thumb_interpreter.cpp)
|
||||
|
||||
# Make this position independent so it can be linked into shared libraries
|
||||
set_property(TARGET MuCoreArmV5TEExperimental
|
||||
PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Currently do not enable the dynamic recompiler
|
||||
set(NO_TRANSLATION)
|
||||
|
||||
# Dynamic Recompiler not supported
|
||||
if(NOT DEFINED NO_TRANSLATION)
|
||||
target_compile_definitions(MuCoreArmV5TEExperimental
|
||||
|
||||
# Disable Dynamic Recompiler (non-portable)
|
||||
PUBLIC NO_TRANSLATION=1)
|
||||
else()
|
||||
# Include Translators
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES aarch64)
|
||||
target_sources(MuCoreArmV5TEExperimental PUBLIC
|
||||
translate_aarch64.cpp)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES arm)
|
||||
target_sources(MuCoreArmV5TEExperimental PUBLIC
|
||||
translate_arm.cpp)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(i386)")
|
||||
target_sources(MuCoreArmV5TEExperimental PUBLIC
|
||||
translate_x86.c)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(x86-64)|(amd64)|(AMD64)")
|
||||
target_sources(MuCoreArmV5TEExperimental PUBLIC
|
||||
translate_x86_64.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Some defines are required for this to function properly
|
||||
target_compile_definitions(MuCoreArmV5TEExperimental
|
||||
# Enable PalmOS Support
|
||||
PUBLIC EMU_SUPPORT_PALM_OS5=1
|
||||
|
||||
# forces the dynarec to use accurate mode and disable Nspire OS hacks
|
||||
PUBLIC SUPPORT_LINUX=1)
|
||||
|
||||
# Windows?
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
target_sources(MuCoreArmV5TEExperimental PUBLIC
|
||||
os/os-win32.c)
|
||||
|
||||
# Everything else?
|
||||
else()
|
||||
target_sources(MuCoreArmV5TEExperimental PUBLIC
|
||||
os/os-linux.c)
|
||||
endif()
|
||||
|
||||
# Includes for the project
|
||||
target_include_directories(MuCoreArmV5TEExperimental PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/include")
|
||||
@@ -1,541 +0,0 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "armv5te/asmcode.h"
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/cpudefs.h"
|
||||
#include "armv5te/debug.h"
|
||||
#include "armv5te/mmu.h"
|
||||
|
||||
// Detect overflow after an addition or subtraction
|
||||
#define ADD_OVERFLOW(left, right, sum) ((int32_t)(((left) ^ (sum)) & ((right) ^ (sum))) < 0)
|
||||
#define SUB_OVERFLOW(left, right, sum) ((int32_t)(((left) ^ (right)) & ((left) ^ (sum))) < 0)
|
||||
|
||||
static uint32_t add(uint32_t left, uint32_t right, int carry, int setcc) {
|
||||
uint32_t sum = left + right + carry;
|
||||
if (!setcc)
|
||||
return sum;
|
||||
|
||||
if (sum < left) carry = 1;
|
||||
if (sum > left) carry = 0;
|
||||
arm.cpsr_c = carry;
|
||||
arm.cpsr_v = ADD_OVERFLOW(left, right, sum);
|
||||
return sum;
|
||||
}
|
||||
|
||||
// "uint8_t shift_val" is correct here. If it is a shift by register, only the bottom 8 bits are looked at.
|
||||
static uint32_t shift(uint32_t value, uint8_t shift_type, uint8_t shift_val, bool setcc, bool has_rs)
|
||||
{
|
||||
if(shift_val == 0)
|
||||
{
|
||||
if(unlikely(!has_rs))
|
||||
{
|
||||
switch(shift_type)
|
||||
{
|
||||
case SH_ROR:
|
||||
{
|
||||
// RRX
|
||||
bool carry = arm.cpsr_c;
|
||||
if(setcc) arm.cpsr_c = value & 1;
|
||||
return value >> 1 | uint32_t(carry) << 31;
|
||||
}
|
||||
case SH_ASR:
|
||||
case SH_LSR: // #32 is encoded as LSR #0
|
||||
return shift(value, shift_type, 32, setcc, false);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
else if(likely(shift_val < 32))
|
||||
{
|
||||
switch(shift_type)
|
||||
{
|
||||
case SH_LSL:
|
||||
if(setcc) arm.cpsr_c = (value >> (32 - shift_val)) & 1;
|
||||
return value << shift_val;
|
||||
case SH_LSR:
|
||||
if(setcc) arm.cpsr_c = (value >> (shift_val - 1)) & 1;
|
||||
return value >> shift_val;
|
||||
case SH_ASR:
|
||||
if(setcc) arm.cpsr_c = (value >> (shift_val - 1)) & 1;
|
||||
if(value & (1u << 31)) //TODO: Verify!
|
||||
return ~((~value) >> shift_val);
|
||||
else
|
||||
return value >> shift_val;
|
||||
case SH_ROR:
|
||||
if(setcc) arm.cpsr_c = (value >> (shift_val - 1)) & 1;
|
||||
return value >> shift_val | (value << (32 - shift_val));
|
||||
}
|
||||
}
|
||||
else if(shift_val == 32 || shift_type == SH_ASR || shift_type == SH_ROR)
|
||||
{
|
||||
switch(shift_type)
|
||||
{
|
||||
case SH_LSL: if(setcc) arm.cpsr_c = value & 1; return 0;
|
||||
case SH_LSR: if(setcc) arm.cpsr_c = !!(value & (1u << 31)); return 0;
|
||||
case SH_ASR: if(setcc) arm.cpsr_c = !!(value & (1u << 31));
|
||||
if(value & (1u << 31))
|
||||
return 0xFFFFFFFF;
|
||||
else
|
||||
return 0x00000000;
|
||||
case SH_ROR: return shift(value, SH_ROR, shift_val & 0b11111, setcc, false);
|
||||
}
|
||||
}
|
||||
else // shift_val > 32
|
||||
{
|
||||
if(setcc)
|
||||
arm.cpsr_c = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t addr_mode_2(Instruction i)
|
||||
{
|
||||
if(!i.mem_proc.not_imm)
|
||||
return i.mem_proc.immed;
|
||||
|
||||
return shift(reg_pc(i.mem_proc.rm), i.mem_proc.shift, i.mem_proc.shift_imm, false, false);
|
||||
}
|
||||
|
||||
static uint32_t rotated_imm(Instruction i, bool setcc)
|
||||
{
|
||||
uint32_t imm = i.data_proc.immed_8;
|
||||
uint8_t count = i.data_proc.rotate_imm << 1;
|
||||
if(count == 0)
|
||||
return imm;
|
||||
|
||||
imm = (imm >> count) | (imm << (32 - count));
|
||||
if(setcc)
|
||||
arm.cpsr_c = !!(imm & (1u << 31));
|
||||
return imm;
|
||||
}
|
||||
|
||||
static uint32_t addr_mode_1(Instruction i, bool setcc)
|
||||
{
|
||||
if(i.data_proc.imm)
|
||||
return rotated_imm(i, setcc);
|
||||
|
||||
if(i.data_proc.reg_shift)
|
||||
return shift(reg_pc(i.data_proc.rm), i.data_proc.shift, reg(i.data_proc.rs), setcc, true);
|
||||
else
|
||||
return shift(reg_pc(i.data_proc.rm), i.data_proc.shift, i.data_proc.shift_imm, setcc, false);
|
||||
}
|
||||
|
||||
static inline void set_nz_flags(uint32_t value) {
|
||||
arm.cpsr_n = value >> 31;
|
||||
arm.cpsr_z = value == 0;
|
||||
}
|
||||
|
||||
static inline void set_nz_flags_64(uint64_t value) {
|
||||
arm.cpsr_n = value >> 63;
|
||||
arm.cpsr_z = value == 0;
|
||||
}
|
||||
|
||||
void do_arm_instruction(Instruction i)
|
||||
{
|
||||
bool exec = true;
|
||||
|
||||
// Shortcut for unconditional instructions
|
||||
if(likely(i.cond == CC_AL))
|
||||
goto always;
|
||||
|
||||
switch(i.cond)
|
||||
{
|
||||
case CC_EQ: case CC_NE: exec = arm.cpsr_z; break;
|
||||
case CC_CS: case CC_CC: exec = arm.cpsr_c; break;
|
||||
case CC_MI: case CC_PL: exec = arm.cpsr_n; break;
|
||||
case CC_VS: case CC_VC: exec = arm.cpsr_v; break;
|
||||
case CC_HI: case CC_LS: exec = !arm.cpsr_z && arm.cpsr_c; break;
|
||||
case CC_GE: case CC_LT: exec = arm.cpsr_n == arm.cpsr_v; break;
|
||||
case CC_GT: case CC_LE: exec = !arm.cpsr_z && arm.cpsr_n == arm.cpsr_v; break;
|
||||
case CC_NV:
|
||||
if((i.raw & 0xFD70F000) == 0xF550F000)
|
||||
return;
|
||||
else if((i.raw & 0xFE000000) == 0xFA000000)
|
||||
{
|
||||
// BLX
|
||||
arm.reg[14] = arm.reg[15];
|
||||
arm.reg[15] += 4 + ((int32_t) (i.raw << 8) >> 6) + (i.raw >> 23 & 2);//TODO: this signed int shift is undefined behavior by the C standard
|
||||
arm.cpsr_low28 |= 0x20; // Enter Thumb mode
|
||||
return;
|
||||
}
|
||||
else
|
||||
undefined_instruction();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
exec ^= i.cond & 1;
|
||||
|
||||
if(!exec)
|
||||
return;
|
||||
|
||||
always:
|
||||
uint32_t insn = i.raw;
|
||||
|
||||
if((insn & 0xE000090) == 0x0000090)
|
||||
{
|
||||
// MUL, SWP, etc.
|
||||
// LDRH, STRSH, etc.
|
||||
int type = insn >> 5 & 3;
|
||||
if (type == 0) {
|
||||
if ((insn & 0xFC000F0) == 0x0000090) {
|
||||
/* MUL, MLA: 32x32 to 32 multiplications */
|
||||
uint32_t res = reg(insn & 15)
|
||||
* reg(insn >> 8 & 15);
|
||||
if (insn & 0x0200000)
|
||||
res += reg(insn >> 12 & 15);
|
||||
|
||||
set_reg(insn >> 16 & 15, res);
|
||||
if (insn & 0x0100000) set_nz_flags(res);
|
||||
} else if ((insn & 0xF8000F0) == 0x0800090) {
|
||||
/* UMULL, UMLAL, SMULL, SMLAL: 32x32 to 64 multiplications */
|
||||
uint32_t left = reg(insn & 15);
|
||||
uint32_t right = reg(insn >> 8 & 15);
|
||||
uint32_t reg_lo = insn >> 12 & 15;
|
||||
uint32_t reg_hi = insn >> 16 & 15;
|
||||
|
||||
if (reg_lo == reg_hi)
|
||||
error("RdLo and RdHi cannot be same for 64-bit multiply");
|
||||
|
||||
uint64_t res;
|
||||
if (insn & 0x0400000) res = (int64_t)(int32_t)left * (int32_t)right;
|
||||
else res = (uint64_t)left * right;
|
||||
if (insn & 0x0200000) {
|
||||
/* Accumulate */
|
||||
res += (uint64_t)reg(reg_hi) << 32 | reg(reg_lo);
|
||||
}
|
||||
|
||||
set_reg(reg_lo, res);
|
||||
set_reg(reg_hi, res >> 32);
|
||||
if (insn & 0x0100000) set_nz_flags_64(res);
|
||||
} else if ((insn & 0xFB00FF0) == 0x1000090) {
|
||||
/* SWP, SWPB */
|
||||
uint32_t addr = reg(insn >> 16 & 15);
|
||||
uint32_t ld, st = reg(insn & 15);
|
||||
if (insn & 0x0400000) {
|
||||
ld = read_byte(addr); write_byte(addr, st);
|
||||
} else {
|
||||
ld = read_word(addr); write_word(addr, st);
|
||||
}
|
||||
set_reg(insn >> 12 & 15, ld);
|
||||
} else {
|
||||
undefined_instruction();
|
||||
}
|
||||
} else {
|
||||
/* Load/store halfword, signed byte/halfword, or doubleword */
|
||||
int base_reg = insn >> 16 & 15;
|
||||
int data_reg = insn >> 12 & 15;
|
||||
int offset = (insn & (1 << 22))
|
||||
? (insn & 0x0F) | (insn >> 4 & 0xF0)
|
||||
: reg(insn & 15);
|
||||
bool writeback = false;
|
||||
uint32_t addr = reg_pc(base_reg);
|
||||
|
||||
if (!(insn & (1 << 23))) // Subtracted offset
|
||||
offset = -offset;
|
||||
|
||||
if (insn & (1 << 24)) { // Offset or pre-indexed addressing
|
||||
addr += offset;
|
||||
offset = 0;
|
||||
writeback = insn & (1 << 21);
|
||||
} else {
|
||||
if(insn & (1 << 21))
|
||||
mmu_check_priv(addr, !((insn & (1 << 20)) || type == 2));
|
||||
|
||||
writeback = true;
|
||||
}
|
||||
|
||||
if (insn & (1 << 20)) {
|
||||
uint32_t data;
|
||||
if (base_reg == data_reg && writeback)
|
||||
error("Load instruction modifies base register twice");
|
||||
if (type == 1) data = read_half(addr); /* LDRH */
|
||||
else if (type == 2) data = (int8_t) read_byte(addr); /* LDRSB */
|
||||
else data = (int16_t)read_half(addr); /* LDRSH */
|
||||
set_reg(data_reg, data);
|
||||
} else if (type == 1) { /* STRH */
|
||||
write_half(addr, reg(data_reg));
|
||||
} else {
|
||||
if (data_reg & 1) error("LDRD/STRD with odd-numbered data register");
|
||||
if (type == 2) { /* LDRD */
|
||||
if ((base_reg & ~1) == data_reg && writeback)
|
||||
error("Load instruction modifies base register twice");
|
||||
uint32_t low = read_word(addr);
|
||||
uint32_t high = read_word(addr + 4);
|
||||
set_reg(data_reg, low);
|
||||
set_reg(data_reg + 1, high);
|
||||
} else { /* STRD */
|
||||
write_word(addr, reg(data_reg));
|
||||
write_word(addr + 4, reg(data_reg + 1));
|
||||
}
|
||||
}
|
||||
if (writeback)
|
||||
set_reg(base_reg, addr + offset);
|
||||
}
|
||||
}
|
||||
else if((insn & 0xD900000) == 0x1000000)
|
||||
{
|
||||
// BLX, MRS, MSR, SMUL, etc.
|
||||
if ((insn & 0xFFFFFD0) == 0x12FFF10) {
|
||||
/* B(L)X: Branch(, link,) and exchange T bit */
|
||||
uint32_t target = reg_pc(insn & 15);
|
||||
if (insn & 0x20)
|
||||
arm.reg[14] = arm.reg[15];
|
||||
set_reg_bx(15, target);
|
||||
} else if ((insn & 0xFBF0FFF) == 0x10F0000) {
|
||||
/* MRS: Move reg <- status */
|
||||
set_reg(insn >> 12 & 15, (insn & 0x0400000) ? get_spsr() : get_cpsr());
|
||||
} else if ((insn & 0xFB0FFF0) == 0x120F000 ||
|
||||
(insn & 0xFB0F000) == 0x320F000) {
|
||||
/* MSR: Move status <- reg/imm */
|
||||
uint32_t val, mask = 0;
|
||||
if (insn & 0x2000000)
|
||||
val = rotated_imm(i, false);
|
||||
else
|
||||
val = reg(insn & 15);
|
||||
if (insn & 0x0080000) mask |= 0xFF000000;
|
||||
if (insn & 0x0040000) mask |= 0x00FF0000;
|
||||
if (insn & 0x0020000) mask |= 0x0000FF00;
|
||||
if (insn & 0x0010000) mask |= 0x000000FF;
|
||||
if (insn & 0x0400000)
|
||||
set_spsr(val, mask);
|
||||
else
|
||||
set_cpsr(val, mask);
|
||||
} else if ((insn & 0xF900090) == 0x1000080) {
|
||||
int32_t left = reg(insn & 15);
|
||||
int16_t right = reg((insn >> 8) & 15) >> ((insn & 0x40) ? 16 : 0);
|
||||
int32_t product;
|
||||
int type = insn >> 21 & 3;
|
||||
|
||||
if (type == 1) {
|
||||
/* SMULW<y>, SMLAW<y>: Signed 32x16 to 48 multiply, uses only top 32 bits */
|
||||
product = (int64_t)left * right >> 16;
|
||||
if (!(insn & 0x20))
|
||||
goto accumulate;
|
||||
} else {
|
||||
/* SMUL<x><y>, SMLA<x><y>, SMLAL<x><y>: Signed 16x16 to 32 multiply */
|
||||
product = (int16_t)(left >> ((insn & 0x20) ? 16 : 0)) * right;
|
||||
}
|
||||
if (type == 2) {
|
||||
/* SMLAL<x><y>: 64-bit accumulate */
|
||||
uint32_t reg_lo = insn >> 12 & 15;
|
||||
uint32_t reg_hi = insn >> 16 & 15;
|
||||
int64_t sum;
|
||||
if (reg_lo == reg_hi)
|
||||
error("RdLo and RdHi cannot be same for 64-bit accumulate");
|
||||
sum = product + ((uint64_t)reg(reg_hi) << 32 | reg(reg_lo));
|
||||
set_reg(reg_lo, sum);
|
||||
set_reg(reg_hi, sum >> 32);
|
||||
} else if (type == 0) accumulate: {
|
||||
/* SMLA<x><y>, SMLAW<y>: 32-bit accumulate */
|
||||
int32_t acc = reg(insn >> 12 & 15);
|
||||
int32_t sum = product + acc;
|
||||
/* Set Q flag on overflow */
|
||||
arm.cpsr_low28 |= ADD_OVERFLOW(product, acc, sum) << 27;
|
||||
set_reg(insn >> 16 & 15, sum);
|
||||
} else {
|
||||
/* SMUL<x><y>, SMULW<y>: No accumulate */
|
||||
set_reg(insn >> 16 & 15, product);
|
||||
}
|
||||
} else if ((insn & 0xF900FF0) == 0x1000050) {
|
||||
/* QADD, QSUB, QDADD, QDSUB: Saturated arithmetic */
|
||||
int32_t left = reg(insn & 15);
|
||||
int32_t right = reg(insn >> 16 & 15);
|
||||
int32_t res, overflow;
|
||||
if (insn & 0x400000) {
|
||||
/* Doubled right operand */
|
||||
res = right << 1;
|
||||
if (ADD_OVERFLOW(right, right, res)) {
|
||||
/* Overflow, set Q flag and saturate */
|
||||
arm.cpsr_low28 |= 1 << 27;
|
||||
res = (res < 0) ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
right = res;
|
||||
}
|
||||
if (!(insn & 0x200000)) {
|
||||
res = left + right;
|
||||
overflow = ADD_OVERFLOW(left, right, res);
|
||||
} else {
|
||||
res = left - right;
|
||||
overflow = SUB_OVERFLOW(left, right, res);
|
||||
}
|
||||
if (overflow) {
|
||||
/* Set Q flag and saturate */
|
||||
arm.cpsr_low28 |= 1 << 27;
|
||||
res = (res < 0) ? 0x7FFFFFFF : 0x80000000;
|
||||
}
|
||||
set_reg(insn >> 12 & 15, res);
|
||||
} else if ((insn & 0xFFF0FF0) == 0x16F0F10) {
|
||||
/* CLZ: Count leading zeros */
|
||||
int32_t value = reg(insn & 15);
|
||||
uint32_t zeros;
|
||||
for (zeros = 0; zeros < 32 && value >= 0; zeros++)
|
||||
value <<= 1;
|
||||
set_reg(insn >> 12 & 15, zeros);
|
||||
} else if ((insn & 0xFFF000F0) == 0xE1200070) {
|
||||
gui_debug_printf("Software breakpoint at %08X (%04X)\n",
|
||||
arm.reg[15], (insn >> 4 & 0xFFF0) | (insn & 0xF));
|
||||
debugger(DBG_EXEC_BREAKPOINT, 0);
|
||||
} else
|
||||
undefined_instruction();
|
||||
}
|
||||
else if(likely((insn & 0xC000000) == 0x0000000))
|
||||
{
|
||||
// Data processing
|
||||
bool carry = arm.cpsr_c,
|
||||
setcc = i.data_proc.s;
|
||||
|
||||
uint32_t left = reg_pc(i.data_proc.rn),
|
||||
right = addr_mode_1(i, setcc),
|
||||
res = 0;
|
||||
|
||||
switch(i.data_proc.op)
|
||||
{
|
||||
case OP_AND: res = left & right; break;
|
||||
case OP_EOR: res = left ^ right; break;
|
||||
case OP_SUB: res = add( left, ~right, 1, setcc); break;
|
||||
case OP_RSB: res = add(~left, right, 1, setcc); break;
|
||||
case OP_ADD: res = add( left, right, 0, setcc); break;
|
||||
case OP_ADC: res = add( left, right, carry, setcc); break;
|
||||
case OP_SBC: res = add( left, ~right, carry, setcc); break;
|
||||
case OP_RSC: res = add(~left, right, carry, setcc); break;
|
||||
case OP_TST: res = left & right; break;
|
||||
case OP_TEQ: res = left ^ right; break;
|
||||
case OP_CMP: res = add( left, ~right, 1, setcc); break;
|
||||
case OP_CMN: res = add( left, right, 0, setcc); break;
|
||||
case OP_ORR: res = left | right; break;
|
||||
case OP_MOV: res = right; break;
|
||||
case OP_BIC: res = left & ~right; break;
|
||||
case OP_MVN: res = ~right; break;
|
||||
}
|
||||
|
||||
if(i.data_proc.op < OP_TST || i.data_proc.op > OP_CMN)
|
||||
set_reg_pc(i.data_proc.rd, res);
|
||||
|
||||
if(setcc)
|
||||
{
|
||||
// Used for returning from exceptions, for instance
|
||||
if(i.data_proc.rd == 15)
|
||||
set_cpsr_full(get_spsr());
|
||||
else
|
||||
{
|
||||
arm.cpsr_n = res >> 31;
|
||||
arm.cpsr_z = res == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((insn & 0xFF000F0) == 0x7F000F0)
|
||||
undefined_instruction();
|
||||
else if((insn & 0xC000000) == 0x4000000)
|
||||
{
|
||||
// LDR, STRB, etc.
|
||||
uint32_t base = reg_pc(i.mem_proc.rn),
|
||||
offset = addr_mode_2(i);
|
||||
if(!i.mem_proc.u)
|
||||
offset = -offset;
|
||||
|
||||
// Pre-indexed or offset
|
||||
if(i.mem_proc.p)
|
||||
base += offset; // Writeback for pre-indexed handled after access
|
||||
else if(i.mem_proc.w) // Usermode Access
|
||||
mmu_check_priv(base, !i.mem_proc.l);
|
||||
|
||||
// Byte access
|
||||
if(i.mem_proc.b)
|
||||
{
|
||||
if(i.mem_proc.l) set_reg_bx(i.mem_proc.rd, read_byte(base));
|
||||
else write_byte(base, reg_pc_mem(i.mem_proc.rd));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(i.mem_proc.l) set_reg_bx(i.mem_proc.rd, read_word(base));
|
||||
else write_word(base, reg_pc_mem(i.mem_proc.rd));
|
||||
}
|
||||
|
||||
// Post-indexed addressing
|
||||
if(!i.mem_proc.p)
|
||||
base += offset;
|
||||
|
||||
// Writeback
|
||||
if(!i.mem_proc.p || i.mem_proc.w)
|
||||
set_reg(i.mem_proc.rn, base);
|
||||
}
|
||||
else if((insn & 0xE000000) == 0x8000000)
|
||||
{
|
||||
// LDM, STM, etc.
|
||||
int base_reg = insn >> 16 & 15;
|
||||
uint32_t addr = reg(base_reg);
|
||||
uint32_t new_base = addr;
|
||||
int count = __builtin_popcount(i.mem_multi.reglist);
|
||||
|
||||
if (i.mem_multi.u) { // Increasing
|
||||
if (i.mem_multi.w) // Writeback
|
||||
new_base += count * 4;
|
||||
if (i.mem_multi.p) // Preincrement
|
||||
addr += 4;
|
||||
} else { // Decreasing
|
||||
addr -= count * 4;
|
||||
if (i.mem_multi.w) // Writeback
|
||||
new_base = addr;
|
||||
if (!i.mem_multi.p) // Postdecrement
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
for (unsigned reg = 0, reglist = i.mem_multi.reglist; reglist && reg < 15; reglist >>= 1, reg++) {
|
||||
if ((reglist & 1) == 0)
|
||||
continue;
|
||||
|
||||
uint32_t *reg_ptr = &arm.reg[reg];
|
||||
if (i.mem_multi.s && !i.mem_multi.w && !(i.mem_multi.reglist & (1<<15))) {
|
||||
// User-mode registers
|
||||
int mode = arm.cpsr_low28 & 0x1F;
|
||||
if (reg >= 13) {
|
||||
if (mode != MODE_USR && mode != MODE_SYS) reg_ptr = &arm.r13_usr[reg - 13];
|
||||
} else if (reg >= 8) {
|
||||
if (mode == MODE_FIQ) reg_ptr = &arm.r8_usr[reg - 8];
|
||||
}
|
||||
}
|
||||
if (i.mem_multi.l) { // Load
|
||||
if (reg_ptr == &arm.reg[base_reg]) {
|
||||
if (i.mem_multi.w) // Writeback
|
||||
error("Load instruction modifies base register twice");
|
||||
reg_ptr = &new_base;
|
||||
}
|
||||
*reg_ptr = read_word(addr);
|
||||
} else { // Store
|
||||
write_word(addr, *reg_ptr);
|
||||
}
|
||||
addr += 4;
|
||||
}
|
||||
if (i.mem_multi.reglist & (1 << 15)) {
|
||||
if (i.mem_multi.l) // Load
|
||||
set_reg_bx(15, read_word(addr));
|
||||
else // Store
|
||||
write_word(addr, reg_pc_mem(15));
|
||||
}
|
||||
arm.reg[base_reg] = new_base;
|
||||
if (i.mem_multi.l && i.mem_multi.s && i.mem_multi.reglist & (1<<15))
|
||||
set_cpsr_full(get_spsr());
|
||||
}
|
||||
else if((insn & 0xE000000) == 0xA000000)
|
||||
{
|
||||
// B and BL
|
||||
if(i.branch.l)
|
||||
arm.reg[14] = arm.reg[15];
|
||||
arm.reg[15] += (int32_t) (i.branch.immed << 8) >> 6;//TODO: this signed int shift is undefined behavior by the C standard
|
||||
arm.reg[15] += 4;
|
||||
if(arm.reg[15] >= 0x2009B130 && arm.reg[15] <= 0x200C7EEB && i.branch.l)
|
||||
gui_debug_printf("ARM DAL function call, jump from 0x%08X to 0x%08X\n", arm.reg[14] - 4, arm.reg[15]);
|
||||
}
|
||||
else if((insn & 0xF000F10) == 0xE000F10)
|
||||
do_cp15_instruction(i);
|
||||
else if((insn & 0xF000F10) == 0xE000E10)
|
||||
do_cp14_instruction(i);
|
||||
else if((insn & 0xF000000) == 0xF000000)
|
||||
cpu_exception(EX_SWI);
|
||||
else
|
||||
undefined_instruction();
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
#include "armv5te/asmcode.h"
|
||||
#include "armv5te/debug.h"
|
||||
#include "armv5te/mmu.h"
|
||||
#include "armv5te/mem.h"
|
||||
|
||||
//TODO: Read breakpoints, alignment checks
|
||||
|
||||
#if defined(NO_TRANSLATION)
|
||||
void flush_translations() {}
|
||||
#endif
|
||||
|
||||
uint32_t FASTCALL read_word(uint32_t addr)
|
||||
{
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
|
||||
|
||||
//If the sum doesn't contain the address directly
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID) //Invalid entry
|
||||
{
|
||||
addr_cache_miss(addr, false, data_abort);
|
||||
return read_word(addr);
|
||||
}
|
||||
else //Physical address
|
||||
{
|
||||
entry &= ~AC_FLAGS;
|
||||
entry += addr;
|
||||
return mmio_read_word(entry);
|
||||
}
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
|
||||
return *(uint32_t*)entry;
|
||||
}
|
||||
|
||||
uint32_t FASTCALL read_byte(uint32_t addr)
|
||||
{
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
|
||||
|
||||
//If the sum doesn't contain the address directly
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID) //Invalid entry
|
||||
{
|
||||
addr_cache_miss(addr, false, data_abort);
|
||||
return read_byte(addr);
|
||||
}
|
||||
else //Physical address
|
||||
{
|
||||
entry &= ~AC_FLAGS;
|
||||
entry += addr;
|
||||
return mmio_read_byte(entry);
|
||||
}
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
|
||||
return *(uint8_t*)entry;
|
||||
}
|
||||
|
||||
uint32_t FASTCALL read_half(uint32_t addr)
|
||||
{
|
||||
addr &= ~1;
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
|
||||
|
||||
//If the sum doesn't contain the address directly
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID) //Invalid entry
|
||||
{
|
||||
addr_cache_miss(addr, false, data_abort);
|
||||
return read_half(addr);
|
||||
}
|
||||
else //Physical address
|
||||
{
|
||||
entry &= ~AC_FLAGS;
|
||||
entry += addr;
|
||||
return mmio_read_half(entry);
|
||||
}
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
|
||||
return *(uint16_t*)entry;
|
||||
}
|
||||
|
||||
void FASTCALL write_byte(uint32_t addr, uint32_t value)
|
||||
{
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1) + 1);
|
||||
|
||||
//If the sum doesn't contain the address directly
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID) //Invalid entry
|
||||
{
|
||||
addr_cache_miss(addr, true, data_abort);
|
||||
return write_byte(addr, value);
|
||||
}
|
||||
else //Physical address
|
||||
{
|
||||
entry &= ~AC_FLAGS;
|
||||
entry += addr;
|
||||
return mmio_write_byte(entry, value);
|
||||
}
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
|
||||
if(RAM_FLAGS(entry & ~3) & DO_WRITE_ACTION)
|
||||
write_action((void*) entry);
|
||||
*(uint8_t*)entry = value;
|
||||
}
|
||||
|
||||
void FASTCALL write_half(uint32_t addr, uint32_t value)
|
||||
{
|
||||
addr &= ~1;
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1) + 1);
|
||||
|
||||
//If the sum doesn't contain the address directly
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID) //Invalid entry
|
||||
{
|
||||
addr_cache_miss(addr, true, data_abort);
|
||||
return write_half(addr, value);
|
||||
}
|
||||
else //Physical address
|
||||
{
|
||||
entry &= ~AC_FLAGS;
|
||||
entry += addr;
|
||||
return mmio_write_half(entry, value);
|
||||
}
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
|
||||
if(RAM_FLAGS(entry & ~3) & DO_WRITE_ACTION)
|
||||
write_action((void*) entry);
|
||||
*(uint16_t*)entry = value;
|
||||
}
|
||||
|
||||
void FASTCALL write_word(uint32_t addr, uint32_t value)
|
||||
{
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1) + 1);
|
||||
|
||||
//If the sum doesn't contain the address directly
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID) //Invalid entry
|
||||
{
|
||||
addr_cache_miss(addr, true, data_abort);
|
||||
return write_word(addr, value);
|
||||
}
|
||||
else //Physical address
|
||||
{
|
||||
entry &= ~AC_FLAGS;
|
||||
entry += addr;
|
||||
return mmio_write_word(entry, value);
|
||||
}
|
||||
}
|
||||
entry += addr;
|
||||
|
||||
if(RAM_FLAGS(entry & ~3) & DO_WRITE_ACTION)
|
||||
write_action((void*) entry);
|
||||
*(uint32_t*)entry = value;
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
.macro loadsym reg, name
|
||||
#ifdef __clang__
|
||||
adrp \reg, \name\()@PAGE
|
||||
add \reg, \reg, \name\()@PAGEOFF
|
||||
#else
|
||||
adrp \reg, \name
|
||||
add \reg, \reg, #:lo12:\name
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.data
|
||||
.align 3
|
||||
|
||||
.global arm
|
||||
.global cycle_count_delta
|
||||
.global cpu_events
|
||||
.global addr_cache
|
||||
|
||||
translation_sp: .global translation_sp
|
||||
.xword 0
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
.global data_abort
|
||||
|
||||
translation_enter: .global translation_enter
|
||||
stp x19, x30, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
|
||||
// Store s into translation_sp
|
||||
mov x1, sp
|
||||
loadsym x2, translation_sp
|
||||
str x1, [x2]
|
||||
|
||||
loadsym x19, arm
|
||||
loadsym x26, addr_cache
|
||||
ldr x26, [x26]
|
||||
|
||||
bl load_virt
|
||||
b translation_next_enter
|
||||
|
||||
// Enter translation, check for thumb
|
||||
translation_next_bx: .global translation_next_bx
|
||||
tbnz w0, #0, to_thumb // if(pc & 1) goto to_thumb;
|
||||
|
||||
// Enter translation; sets arm.reg[15] = w0
|
||||
translation_next: .global translation_next
|
||||
mrs x17, nzcv
|
||||
str w0, [x19, #15*4]
|
||||
|
||||
mov w1, w0
|
||||
|
||||
lsr x0, x0, #10
|
||||
lsl x0, x0, #4
|
||||
ldr x0, [x26, x0] // x0 = addr_cache[(x0 >> 10) << 1]
|
||||
tbnz x0, #0, save_return // if(x0 & 1) goto save_return;
|
||||
|
||||
// Load RAM_FLAGS
|
||||
add x0, x0, x1 // x0 = pointer to memory at x0
|
||||
|
||||
// Enter translation at x0 (has to be ptr to arm.reg[15]'s memory)
|
||||
translation_next_enter:
|
||||
loadsym x23, cpu_events
|
||||
ldr w23, [x23]
|
||||
cbnz w23, save_return // if(cpu_events) goto save_return;
|
||||
|
||||
mov x21, #80*1024*1024
|
||||
ldr w21, [x0, x21] // w21 = RAM_FLAGS(x0)
|
||||
tbz w21, #5, save_return // if((RAM_FLAGS(x0) & RF_CODE_TRANSLATED) == 0) goto save_return;
|
||||
lsr w21, w21, #9 // w21 = w21 >> RFS_TRANSLATION_INDEX
|
||||
|
||||
loadsym x23, translation_table
|
||||
add x23, x23, x21, lsl #5 // x23 = &translation_table[RAM_FLAGS(x0) >> RFS_TRANSLATION_INDEX]
|
||||
|
||||
ldr x24, [x23, #1*8] // x24 = x3->jump_table
|
||||
ldp x25, x21, [x23, #2*8] // x25 = x23->start_ptr; x21 = x23->end_ptr
|
||||
|
||||
sub x21, x21, x0 // x21 = end_ptr - insn_ptr
|
||||
lsr x21, x21, #2 // x21: number of instructions until the end
|
||||
|
||||
sub x25, x0, x25 // x25 = insn_ptr - start_ptr
|
||||
//lsr x25, x25, #2 // x25 = count of instructions
|
||||
//lsl x25, x25, #3
|
||||
lsl x25, x25, #1
|
||||
ldr x0, [x24, x25] // x0 = jump_table[(insn_ptr - start_ptr) / 4]
|
||||
|
||||
// add number of instructions to cycle_count_delta
|
||||
loadsym x24, cycle_count_delta
|
||||
ldr w25, [x24]
|
||||
add w25, w25, w21
|
||||
str w25, [x24]
|
||||
cmp w25, #0
|
||||
bpl save_return // if(cycle_count_delta > 0) goto save_return;
|
||||
|
||||
msr nzcv, x17
|
||||
br x0
|
||||
|
||||
translation_jmp_ptr: .global translation_jmp_ptr
|
||||
mrs x17, nzcv
|
||||
|
||||
b translation_next_enter
|
||||
|
||||
translation_jmp: .global translation_jmp
|
||||
mrs x17, nzcv
|
||||
|
||||
// add number of instructions to cycle_count_delta
|
||||
loadsym x24, cycle_count_delta
|
||||
ldr w25, [x24]
|
||||
adds w25, w25, #4 // We don't know how much will be executed, so use a possible number
|
||||
bpl save_return
|
||||
str w25, [x24]
|
||||
|
||||
msr nzcv, x17
|
||||
|
||||
br x0
|
||||
|
||||
to_thumb:
|
||||
mrs x17, nzcv
|
||||
sub w0, w0, #1
|
||||
str w0, [x19, #15*4] // arm.reg[15] = w0 - 1
|
||||
ldr w1, [x19, #16*4]
|
||||
orr w1, w1, #0x20
|
||||
str w1, [x19, #16*4] // arm.cpsr_low28 |= 0x20
|
||||
|
||||
save_return:
|
||||
loadsym x0, translation_sp
|
||||
mov x1, #0
|
||||
str x1, [x0]
|
||||
|
||||
bl save_virt
|
||||
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x19, x30, [sp], #16
|
||||
ret
|
||||
|
||||
// Saves the virtual CPU state
|
||||
save_virt:
|
||||
stp w2, w3, [x19, #0*4]
|
||||
stp w4, w5, [x19, #2*4]
|
||||
stp w6, w7, [x19, #4*4]
|
||||
stp w8, w9, [x19, #6*4]
|
||||
stp w10, w11, [x19, #8*4]
|
||||
stp w12, w13, [x19, #10*4]
|
||||
stp w14, w15, [x19, #12*4]
|
||||
str w16, [x19, #14*4]
|
||||
// Save nzcv (in x17) to struct arm_state again
|
||||
ubfx x2, x17, #31, #1
|
||||
ubfx x3, x17, #30, #1
|
||||
ubfx x4, x17, #29, #1
|
||||
ubfx x5, x17, #28, #1
|
||||
strb w2, [x19, #17*4+0]
|
||||
strb w3, [x19, #17*4+1]
|
||||
strb w4, [x19, #17*4+2]
|
||||
strb w5, [x19, #17*4+3]
|
||||
ret
|
||||
|
||||
// Loads the virtual CPU state
|
||||
// x19 has to be a pointer to the arm_state
|
||||
load_virt:
|
||||
// Assemble virtual cpsr_nzcv in x17
|
||||
ldrb w17, [x19, #17*4+0] // x17 = bit 31
|
||||
ldrb w3, [x19, #17*4+1] // w3 = bit 30
|
||||
ldrb w4, [x19, #17*4+2] // w4 = bit 29
|
||||
ldrb w5, [x19, #17*4+3] // w5 = bit 28
|
||||
lsl w17, w17, #31
|
||||
bfi w17, w3, #30, #1
|
||||
bfi w17, w4, #29, #1
|
||||
bfi w17, w5, #28, #1
|
||||
ldp w2, w3, [x19, #0*4]
|
||||
ldp w4, w5, [x19, #2*4]
|
||||
ldp w6, w7, [x19, #4*4]
|
||||
ldp w8, w9, [x19, #6*4]
|
||||
ldp w10, w11, [x19, #8*4]
|
||||
ldp w12, w13, [x19, #10*4]
|
||||
ldp w14, w15, [x19, #12*4]
|
||||
ldr w16, [x19, #14*4]
|
||||
ret
|
||||
|
||||
read_word_asm: .global read_word_asm
|
||||
lsr w22, w0, #10
|
||||
add x21, x26, x22, lsl #4 // x21 = &addr_cache[(x0 >> 10) << 1]
|
||||
0: ldr x22, [x21] // x22 = *x21
|
||||
tbnz x22, #0, 1f
|
||||
ldr w0, [x22, x0]
|
||||
ret
|
||||
|
||||
// Not cached
|
||||
1: tbnz x22, #1, 2f
|
||||
// MMIO
|
||||
bic x22, x22, #3
|
||||
stp x30, x23, [sp, #-16]!
|
||||
add x0, x0, x22
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
bl mmio_read_word
|
||||
bl load_virt
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
ret
|
||||
|
||||
// Invalid
|
||||
2: stp x30, x23, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
mov x1, #0
|
||||
loadsym x2, data_abort
|
||||
bl addr_cache_miss
|
||||
bl load_virt
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
b 0b // Try again
|
||||
|
||||
read_half_asm: .global read_half_asm
|
||||
bic w22, w22, #1
|
||||
lsr w22, w0, #10
|
||||
add x21, x26, x22, lsl #4 // x21 = &addr_cache[(x0 >> 10) << 1]
|
||||
0: ldr x22, [x21] // x22 = *x21
|
||||
tbnz x22, #0, 1f
|
||||
ldrh w0, [x22, x0]
|
||||
ret
|
||||
|
||||
// Not cached
|
||||
1: tbnz x22, #1, 2f
|
||||
// MMIO
|
||||
bic x22, x22, #3
|
||||
stp x30, x23, [sp, #-16]!
|
||||
add x0, x0, x22
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
bl mmio_read_half
|
||||
bl load_virt
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
ret
|
||||
|
||||
// Invalid
|
||||
2: stp x30, x23, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
mov x1, #0
|
||||
loadsym x2, data_abort
|
||||
bl addr_cache_miss
|
||||
bl load_virt
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
b 0b // Try again
|
||||
|
||||
read_byte_asm: .global read_byte_asm
|
||||
lsr w22, w0, #10
|
||||
add x21, x26, x22, lsl #4 // x21 = &addr_cache[(x0 >> 10) << 1]
|
||||
0: ldr x22, [x21] // x22 = *x21
|
||||
tbnz x22, #0, 1f
|
||||
ldrb w0, [x22, x0]
|
||||
ret
|
||||
|
||||
// Not cached
|
||||
1: tbnz x22, #1, 2f
|
||||
// MMIO
|
||||
bic x22, x22, #3
|
||||
stp x30, x23, [sp, #-16]!
|
||||
add x0, x0, x22
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
bl mmio_read_byte
|
||||
bl load_virt
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
ret
|
||||
|
||||
// Invalid
|
||||
2: stp x30, x23, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
mov x1, #0
|
||||
loadsym x2, data_abort
|
||||
bl addr_cache_miss
|
||||
bl load_virt
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
b 0b // Try again
|
||||
|
||||
write_word_asm: .global write_word_asm
|
||||
lsr w22, w0, #10
|
||||
add x21, x26, x22, lsl #4 // x21 = &addr_cache[(x0 >> 10) << 1]
|
||||
0: ldr x22, [x21, #8] // x22 = *(x21+1)
|
||||
tbnz x22, #0, 1f
|
||||
str w1, [x22, x0]
|
||||
ret
|
||||
|
||||
// Not cached
|
||||
1: tbnz x22, #1, 2f
|
||||
// MMIO
|
||||
bic x22, x22, #3
|
||||
stp x30, x23, [sp, #-16]!
|
||||
add x0, x0, x22
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
bl mmio_write_word
|
||||
bl load_virt
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
ret
|
||||
|
||||
// Invalid
|
||||
2: stp x30, x23, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
mov x1, #1
|
||||
loadsym x2, data_abort
|
||||
bl addr_cache_miss
|
||||
bl load_virt
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
b 0b // Try again
|
||||
|
||||
write_half_asm: .global write_half_asm
|
||||
bic w22, w22, #1
|
||||
lsr w22, w0, #10
|
||||
add x21, x26, x22, lsl #4 // x21 = &addr_cache[(x0 >> 10) << 1]
|
||||
0: ldr x22, [x21, #8] // x22 = *(x21+1)
|
||||
tbnz x22, #0, 1f
|
||||
strh w1, [x22, x0]
|
||||
ret
|
||||
|
||||
// Not cached
|
||||
1: tbnz x22, #1, 2f
|
||||
// MMIO
|
||||
bic x22, x22, #3
|
||||
stp x30, x23, [sp, #-16]!
|
||||
add x0, x0, x22
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
bl mmio_write_half
|
||||
bl load_virt
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
ret
|
||||
|
||||
// Invalid
|
||||
2: stp x30, x23, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
mov x1, #1
|
||||
loadsym x2, data_abort
|
||||
bl addr_cache_miss
|
||||
bl load_virt
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
b 0b // Try again
|
||||
|
||||
write_byte_asm: .global write_byte_asm
|
||||
lsr w22, w0, #10
|
||||
add x21, x26, x22, lsl #4 // x21 = &addr_cache[(x0 >> 10) << 1]
|
||||
0: ldr x22, [x21, #8] // x22 = *(x21+1)
|
||||
tbnz x22, #0, 1f
|
||||
strb w1, [x22, x0]
|
||||
ret
|
||||
|
||||
// Not cached
|
||||
1: tbnz x22, #1, 2f
|
||||
// MMIO
|
||||
bic x22, x22, #3
|
||||
stp x30, x23, [sp, #-16]!
|
||||
add x0, x0, x22
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
bl mmio_write_byte
|
||||
bl load_virt
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
ret
|
||||
|
||||
// Invalid
|
||||
2: stp x30, x23, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mrs x17, nzcv
|
||||
bl save_virt
|
||||
mov x1, #1
|
||||
loadsym x2, data_abort
|
||||
bl addr_cache_miss
|
||||
bl load_virt
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x30, x23, [sp], #16
|
||||
msr nzcv, x17
|
||||
b 0b // Try again
|
||||
@@ -1,334 +0,0 @@
|
||||
.data
|
||||
translation_sp: .global translation_sp
|
||||
.word 0
|
||||
.global arm
|
||||
.global get_cpsr_flags
|
||||
.global set_cpsr_flags
|
||||
.global cycle_count_delta
|
||||
.global cpu_events
|
||||
.global read_instruction
|
||||
|
||||
.text
|
||||
|
||||
#ifdef __clang__
|
||||
#define streqh strheq
|
||||
#define streqb strbeq
|
||||
#define ldreqh ldrheq
|
||||
#define ldreqb ldrbeq
|
||||
#endif
|
||||
|
||||
#define RF_CODE_TRANSLATED 32
|
||||
#define RFS_TRANSLATION_INDEX 9
|
||||
|
||||
#define AC_INVALID 0b10
|
||||
#define AC_NOT_PTR 0b01
|
||||
#define AC_FLAGS (AC_INVALID|AC_NOT_PTR)
|
||||
|
||||
#if defined(__clang__)
|
||||
/* On iOS, .text relocations are permitted and due to
|
||||
a bug it's unable to handle our way of
|
||||
avoiding them anyway... */
|
||||
|
||||
.macro sym name, no=1
|
||||
.endm
|
||||
|
||||
.macro loadsym reg, name, no=1
|
||||
ldr \reg, =\name
|
||||
.endm
|
||||
#else
|
||||
|
||||
/* What you can see here is a really bad way of avoiding
|
||||
relocations in the .text section.
|
||||
For each use of an external symbol, you need to insert
|
||||
a sym (name), (number) here, which generates a word containing the
|
||||
distance to the symbol relative to pc.
|
||||
To use it, use loadsym (reg), (name), (number).
|
||||
The whole process is a way of working around
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=18009
|
||||
*/
|
||||
|
||||
.macro sym name, no=1
|
||||
addr_\name\()_\no\(): .word \name - _tmp_\name\()_\no - 8
|
||||
.endm
|
||||
|
||||
.macro loadsym reg, name, no=1
|
||||
ldr \reg, addr_\name\()_\no
|
||||
_tmp_\name\()_\no: add \reg, \reg, pc
|
||||
.endm
|
||||
|
||||
sym translation_sp
|
||||
sym arm
|
||||
sym cpu_events
|
||||
sym translation_table
|
||||
sym cycle_count_delta, 2
|
||||
sym translation_sp, 2
|
||||
//sym cpu_events, 2
|
||||
sym cycle_count_delta, 3
|
||||
sym addr_cache
|
||||
sym data_abort
|
||||
sym addr_cache, 2
|
||||
sym data_abort, 2
|
||||
sym addr_cache, 3
|
||||
sym data_abort, 3
|
||||
sym addr_cache, 4
|
||||
sym data_abort, 4
|
||||
sym addr_cache, 5
|
||||
sym data_abort, 5
|
||||
sym addr_cache, 6
|
||||
sym data_abort, 6
|
||||
|
||||
#endif
|
||||
|
||||
// r0: pointer to the instruction
|
||||
translation_enter: .global translation_enter
|
||||
push {r4-r11, lr}
|
||||
mov r4, r0
|
||||
loadsym r0, translation_sp
|
||||
str sp, [r0]
|
||||
|
||||
bl get_cpsr
|
||||
mov r11, r0 // r11 = cpsr
|
||||
|
||||
mov r0, r4
|
||||
|
||||
add r1, r0, #80*1024*1024 // r1 = &(RAM_FLAGS(r0))
|
||||
ldr r1, [r1]
|
||||
|
||||
loadsym r10, arm // r10 is a pointer to the global arm_state
|
||||
b translation_next_enter
|
||||
|
||||
// r0: pc
|
||||
translation_next_bx: .global translation_next_bx
|
||||
tst r0, #1
|
||||
bne to_thumb
|
||||
|
||||
// r0: pc
|
||||
translation_next: .global translation_next
|
||||
str r0, [r10, #15*4] // save to arm.reg[15]
|
||||
|
||||
bl read_instruction // r0 = pointer to ARM code
|
||||
cmp r0, #0
|
||||
beq save_return
|
||||
|
||||
translation_jmp_ptr: .global translation_jmp_ptr
|
||||
add r1, r0, #80*1024*1024 // r1 = &(RAM_FLAGS(r0))
|
||||
ldr r1, [r1]
|
||||
tst r1, #RF_CODE_TRANSLATED
|
||||
beq save_return // not translated
|
||||
|
||||
// r0: pointer to instruction
|
||||
// r1: RAM_FLAGS(r0)
|
||||
translation_next_enter:
|
||||
loadsym r2, cpu_events
|
||||
ldr r2, [r2]
|
||||
cmp r2, #0
|
||||
bne save_return
|
||||
|
||||
mov r1, r1, lsr #RFS_TRANSLATION_INDEX // r1 is translation index
|
||||
mov r1, r1, lsl #4
|
||||
loadsym r2, translation_table
|
||||
add r1, r2, r1 // r1 points to struct translation now
|
||||
|
||||
ldr r2, [r1, #1*4] // load translation.jump_table
|
||||
ldr r3, [r1, #2*4] // load translation.start_ptr
|
||||
ldr r4, [r1, #3*4] // load translation.end_ptr
|
||||
|
||||
sub r4, r4, r0 // r4 = end_ptr - pc_ptr
|
||||
mov r4, r4, lsr #2 // r4 = number of instructions to the end
|
||||
loadsym r6, cycle_count_delta, 2
|
||||
ldr r5, [r6]
|
||||
add r5, r5, r4 // add r4 to cycle_count_delta
|
||||
str r5, [r6]
|
||||
cmp r5, #0
|
||||
bpl save_return
|
||||
|
||||
sub r0, r0, r3 // r0 = pc_ptr - start_ptr
|
||||
msr cpsr_f, r11
|
||||
ldr pc, [r2, r0] // jump to jump_table[r0]
|
||||
|
||||
to_thumb:
|
||||
sub r0, r0, #1
|
||||
str r0, [r10, #15*4] // arm.reg[PC] = r0
|
||||
ldr r1, [r10, #16*4]
|
||||
orr r1, r1, #0x20 // Set thumb bit
|
||||
str r1, [r10, #16*4]
|
||||
b save_return
|
||||
|
||||
// Invoked from within translated code to jump to other, already translated code
|
||||
// Target address of translated code is in r0 - only r10 and r11 have to be preserved
|
||||
// This is used to check for events and leave the translation to process them.
|
||||
// arm.reg[15] must be set already!
|
||||
translation_jmp: .global translation_jmp
|
||||
/* loadsym r1, cpu_events, 2
|
||||
ldr r2, [r1]
|
||||
cmp r2, #0
|
||||
bne save_return*/
|
||||
|
||||
loadsym r1, cycle_count_delta, 3
|
||||
ldr r2, [r1]
|
||||
add r2, #4 // We don't know how much will be executed, so use a possible number
|
||||
str r2, [r1]
|
||||
cmp r2, #0
|
||||
bpl save_return
|
||||
|
||||
msr cpsr_f, r11
|
||||
bx r0 // Jump to the target
|
||||
|
||||
// Save flags and leave, arm.reg[15] must be set already!
|
||||
save_return:
|
||||
loadsym r1, translation_sp, 2
|
||||
mov r0, #0
|
||||
str r0, [r1]
|
||||
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
mov r0, r11 // apply arm.cpsr_flags to arm.cpsr_*
|
||||
|
||||
pop {r4-r11, lr}
|
||||
|
||||
b set_cpsr_flags
|
||||
|
||||
// Below is basically a handcoded assembly version of asmcode.c
|
||||
//TODO: Invoke write_action for translation invalidation!
|
||||
|
||||
write_word_asm: .global write_word_asm
|
||||
// r0 is address, r1 is value
|
||||
loadsym r2, addr_cache
|
||||
ldr r2, [r2]
|
||||
mov r3, r0, lsr #9
|
||||
orr r3, r3, #1
|
||||
ldr r3, [r2, r3, lsl #2] // r3 contains ac_entry
|
||||
tst r3, #AC_FLAGS
|
||||
streq r1, [r3, r0]
|
||||
bxeq lr
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
tst r3, #AC_INVALID
|
||||
bne write_word_invalid
|
||||
bic r3, #AC_FLAGS
|
||||
add r0, r3, r0
|
||||
b mmio_write_word
|
||||
write_word_invalid:
|
||||
push {r0, r1, r2, lr} //r2 for stack alignment
|
||||
mov r1, #1
|
||||
loadsym r2, data_abort
|
||||
bl addr_cache_miss
|
||||
pop {r0, r1, r2, lr}
|
||||
b write_word_asm
|
||||
|
||||
write_half_asm: .global write_half_asm
|
||||
// r0 is address, r1 is value
|
||||
loadsym r2, addr_cache, 2
|
||||
bic r0, r0, #1
|
||||
ldr r2, [r2]
|
||||
mov r3, r0, lsr #9
|
||||
orr r3, r3, #1
|
||||
ldr r3, [r2, r3, lsl #2] // r3 contains ac_entry
|
||||
tst r3, #AC_FLAGS
|
||||
streqh r1, [r3, r0]
|
||||
bxeq lr
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
tst r3, #AC_INVALID
|
||||
bne write_half_invalid
|
||||
bic r3, #AC_FLAGS
|
||||
add r0, r3, r0
|
||||
b mmio_write_half
|
||||
write_half_invalid:
|
||||
push {r0, r1, r2, lr} //r2 for stack alignment
|
||||
mov r1, #1
|
||||
loadsym r2, data_abort, 2
|
||||
bl addr_cache_miss
|
||||
pop {r0, r1, r2, lr}
|
||||
b write_half_asm
|
||||
|
||||
write_byte_asm: .global write_byte_asm
|
||||
// r0 is address, r1 is value
|
||||
loadsym r2, addr_cache, 3
|
||||
ldr r2, [r2]
|
||||
mov r3, r0, lsr #9
|
||||
orr r3, r3, #1
|
||||
ldr r3, [r2, r3, lsl #2] // r3 contains ac_entry
|
||||
tst r3, #AC_FLAGS
|
||||
streqb r1, [r3, r0]
|
||||
bxeq lr
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
tst r3, #AC_INVALID
|
||||
bne write_byte_invalid
|
||||
bic r3, #AC_FLAGS
|
||||
add r0, r3, r0
|
||||
b mmio_write_byte
|
||||
write_byte_invalid:
|
||||
push {r0, r1, r2, lr} //r2 for stack alignment
|
||||
mov r1, #1
|
||||
loadsym r2, data_abort, 3
|
||||
bl addr_cache_miss
|
||||
pop {r0, r1, r2, lr}
|
||||
b write_byte_asm
|
||||
|
||||
read_word_asm: .global read_word_asm
|
||||
// r0 is address
|
||||
loadsym r2, addr_cache, 4
|
||||
ldr r2, [r2]
|
||||
mov r3, r0, lsr #10
|
||||
ldr r3, [r2, r3, lsl #3] // r3 contains ac_entry
|
||||
tst r3, #AC_FLAGS
|
||||
ldreq r0, [r3, r0]
|
||||
bxeq lr
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
tst r3, #AC_INVALID
|
||||
bne read_word_invalid
|
||||
bic r3, #AC_FLAGS
|
||||
add r0, r3, r0
|
||||
b mmio_read_word
|
||||
read_word_invalid:
|
||||
push {r0, lr}
|
||||
mov r1, #0
|
||||
loadsym r2, data_abort, 4
|
||||
bl addr_cache_miss
|
||||
pop {r0, lr}
|
||||
b read_word_asm
|
||||
|
||||
read_half_asm: .global read_half_asm
|
||||
// r0 is address
|
||||
loadsym r2, addr_cache, 5
|
||||
bic r0, r0, #1
|
||||
ldr r2, [r2]
|
||||
mov r3, r0, lsr #10
|
||||
ldr r3, [r2, r3, lsl #3] // r3 contains ac_entry
|
||||
tst r3, #AC_FLAGS
|
||||
ldreqh r0, [r3, r0]
|
||||
bxeq lr
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
tst r3, #AC_INVALID
|
||||
bne read_half_invalid
|
||||
bic r3, #AC_FLAGS
|
||||
add r0, r3, r0
|
||||
b mmio_read_half
|
||||
read_half_invalid:
|
||||
push {r0, lr}
|
||||
mov r1, #0
|
||||
loadsym r2, data_abort, 5
|
||||
bl addr_cache_miss
|
||||
pop {r0, lr}
|
||||
b read_half_asm
|
||||
|
||||
read_byte_asm: .global read_byte_asm
|
||||
// r0 is address
|
||||
loadsym r2, addr_cache, 6
|
||||
ldr r2, [r2]
|
||||
mov r3, r0, lsr #10
|
||||
ldr r3, [r2, r3, lsl #3] // r3 contains ac_entry
|
||||
tst r3, #AC_FLAGS
|
||||
ldreqb r0, [r3, r0]
|
||||
bxeq lr
|
||||
str r11, [r10, #18*4] // save to arm.cpsr_flags
|
||||
tst r3, #AC_INVALID
|
||||
bne read_byte_invalid
|
||||
bic r3, #AC_FLAGS
|
||||
add r0, r3, r0
|
||||
b mmio_read_byte
|
||||
read_byte_invalid:
|
||||
push {r0, lr}
|
||||
mov r1, #0
|
||||
loadsym r2, data_abort, 6
|
||||
bl addr_cache_miss
|
||||
pop {r0, lr}
|
||||
b read_byte_asm
|
||||
@@ -1,496 +0,0 @@
|
||||
// arm_state structure offsets
|
||||
#define ARM_PC 60
|
||||
#define ARM_CPSR 64
|
||||
#define ARM_FLAG_C 70
|
||||
#define ARM_CONTROL 72
|
||||
|
||||
// translation structure offsets
|
||||
#define TRANS_JUMP_TABLE 4
|
||||
#define TRANS_END_PTR 12
|
||||
|
||||
#define RAM_FLAGS (80*1024*1024) // = MEM_MAXSIZE
|
||||
#define RF_READ_BREAKPOINT 1
|
||||
#define RF_WRITE_BREAKPOINT 2
|
||||
#define RF_EXEC_BREAKPOINT 4
|
||||
#define RF_EXEC_DEBUG_NEXT 8
|
||||
#define RF_CODE_TRANSLATED 32
|
||||
#define RF_CODE_NO_TRANSLATE 64
|
||||
#define RF_READ_ONLY 128
|
||||
#define RF_ARMLOADER_CB 256
|
||||
#define RFS_TRANSLATION_INDEX 9
|
||||
|
||||
#define WRITE_SPECIAL_FLAGS 2+32+64
|
||||
|
||||
// List of locations of addresses which need to be relocated to addr_cache
|
||||
// (necessary since it's now allocated at runtime)
|
||||
.data
|
||||
.globl ac_reloc_start
|
||||
ac_reloc_start:
|
||||
|
||||
.macro AC_RELOC; 0: .data; .long 0b - 4; .text; .endm
|
||||
|
||||
.text
|
||||
.globl translation_enter
|
||||
translation_enter:
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
movl %esp, in_translation_esp
|
||||
|
||||
movl $arm, %ebx
|
||||
movl ARM_PC(%ebx), %eax
|
||||
jmp translation_next
|
||||
|
||||
.globl translation_next_bx
|
||||
translation_next_bx:
|
||||
testb $1, %al
|
||||
jne switch_to_thumb
|
||||
|
||||
.globl translation_next
|
||||
translation_next:
|
||||
movl %eax, ARM_PC(%ebx)
|
||||
|
||||
cmpl $0, cycle_count_delta
|
||||
jns return
|
||||
|
||||
cmpl $0, cpu_events
|
||||
jnz return
|
||||
|
||||
// eax = VM_MEM_PTR(eax)
|
||||
movl %eax, %ecx
|
||||
shrl $10, %ecx
|
||||
addl 0(, %ecx, 8), %eax
|
||||
AC_RELOC
|
||||
testl $0x80000003, %eax
|
||||
jnz return
|
||||
addr_ok:
|
||||
|
||||
movl RAM_FLAGS(%eax), %edx
|
||||
testb $RF_CODE_TRANSLATED, %dl
|
||||
jz return // Not translated
|
||||
|
||||
movl %eax, in_translation_pc_ptr
|
||||
|
||||
shrl $RFS_TRANSLATION_INDEX, %edx
|
||||
shll $4, %edx
|
||||
addl $translation_table, %edx
|
||||
|
||||
// Add one cycle for each instruction from this point to the end
|
||||
movl TRANS_END_PTR(%edx), %ecx
|
||||
subl %eax, %ecx
|
||||
shrl $2, %ecx
|
||||
addl %ecx, cycle_count_delta
|
||||
|
||||
movl TRANS_JUMP_TABLE(%edx), %edx
|
||||
jmp *(%edx, %eax)
|
||||
|
||||
return:
|
||||
andl $0, in_translation_esp
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
switch_to_thumb:
|
||||
decl %eax
|
||||
movl %eax, ARM_PC(%ebx)
|
||||
orb $0x20, ARM_CPSR(%ebx)
|
||||
jmp return
|
||||
|
||||
// These shift procedures are called only from translated code,
|
||||
// so they may assume that %ebx == _arm
|
||||
.align 4
|
||||
.globl arm_shift_proc
|
||||
arm_shift_proc:
|
||||
.long lsl
|
||||
.long lsr
|
||||
.long asr
|
||||
.long 0
|
||||
.long lsl_carry
|
||||
.long lsr_carry
|
||||
.long asr_carry
|
||||
.long ror_carry
|
||||
|
||||
.text
|
||||
lsl:
|
||||
cmpb $32, %cl
|
||||
jae ls_32
|
||||
shll %cl, %eax
|
||||
ret
|
||||
|
||||
lsr:
|
||||
cmpb $32, %cl
|
||||
jae ls_32
|
||||
shrl %cl, %eax
|
||||
ret
|
||||
ls_32:
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
|
||||
asr:
|
||||
cmpb $32, %cl
|
||||
jae asr_32
|
||||
sarl %cl, %eax
|
||||
ret
|
||||
asr_32:
|
||||
sarl $31, %eax
|
||||
ret
|
||||
|
||||
lsl_carry:
|
||||
cmpb $32, %cl
|
||||
jae lsl_carry_32
|
||||
testb %cl, %cl
|
||||
je lsl_carry_zero
|
||||
shll %cl, %eax
|
||||
setc ARM_FLAG_C(%ebx)
|
||||
lsl_carry_zero:
|
||||
ret
|
||||
lsl_carry_32:
|
||||
jne ls_carry_33
|
||||
shrl $1, %eax
|
||||
setc ARM_FLAG_C(%ebx)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
|
||||
lsr_carry:
|
||||
cmpb $32, %cl
|
||||
jae lsr_carry_32
|
||||
testb %cl, %cl
|
||||
je lsr_carry_zero
|
||||
shrl %cl, %eax
|
||||
setc ARM_FLAG_C(%ebx)
|
||||
lsr_carry_zero:
|
||||
ret
|
||||
lsr_carry_32:
|
||||
jne ls_carry_33
|
||||
shll $1, %eax
|
||||
setc ARM_FLAG_C(%ebx)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
ls_carry_33:
|
||||
xorl %eax, %eax
|
||||
movb %al, ARM_FLAG_C(%ebx)
|
||||
ret
|
||||
|
||||
asr_carry:
|
||||
cmpb $32, %cl
|
||||
jae asr_carry_32
|
||||
testb %cl, %cl
|
||||
je asr_carry_zero
|
||||
sarl %cl, %eax
|
||||
setc ARM_FLAG_C(%ebx)
|
||||
asr_carry_zero:
|
||||
ret
|
||||
asr_carry_32:
|
||||
sarl $31, %eax
|
||||
sets ARM_FLAG_C(%ebx)
|
||||
ret
|
||||
|
||||
ror_carry:
|
||||
testb $31, %cl
|
||||
jz ror_carry_mult_32
|
||||
rorl %cl, %eax
|
||||
setc ARM_FLAG_C(%ebx)
|
||||
ror_carry_zero:
|
||||
ret
|
||||
ror_carry_mult_32:
|
||||
testb %cl, %cl
|
||||
je ror_carry_zero
|
||||
testl %eax, %eax
|
||||
sets ARM_FLAG_C(%ebx)
|
||||
ret
|
||||
|
||||
// uint32_t FASTCALL read_byte(uint32_t addr);
|
||||
.globl read_byte
|
||||
.align 16
|
||||
read_byte:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 0(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
js rb_slow
|
||||
movl %ecx, %edx
|
||||
andl $-4, %edx
|
||||
testb $RF_READ_BREAKPOINT, RAM_FLAGS(%edx)
|
||||
jnz rb_special
|
||||
rb_fast:
|
||||
movzbl (%ecx), %eax
|
||||
ret
|
||||
rb_special:
|
||||
call read_special
|
||||
jmp rb_fast
|
||||
rb_slow:
|
||||
movl 0(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
shll $10, %eax
|
||||
jc rb_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_read_byte
|
||||
rb_miss:
|
||||
call read_miss
|
||||
jmp read_byte
|
||||
|
||||
// uint32_t FASTCALL read_half(uint32_t addr);
|
||||
.globl read_half
|
||||
.align 16
|
||||
read_half:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 0(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
testl $0x80000001, %ecx
|
||||
jnz rh_slow
|
||||
movl %ecx, %edx
|
||||
andl $-4, %edx
|
||||
testb $RF_READ_BREAKPOINT, RAM_FLAGS(%edx)
|
||||
jnz rh_special
|
||||
rh_fast:
|
||||
movzwl (%ecx), %eax
|
||||
ret
|
||||
rh_special:
|
||||
call read_special
|
||||
jmp rh_fast
|
||||
rh_slow:
|
||||
movl 0(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
testl $1, %ecx
|
||||
jnz rh_unaligned
|
||||
shll $10, %eax
|
||||
jc rh_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_read_half
|
||||
rh_miss:
|
||||
call read_miss
|
||||
jmp read_half
|
||||
rh_unaligned:
|
||||
call align_fault
|
||||
decl %ecx
|
||||
jmp read_half
|
||||
|
||||
// uint32_t FASTCALL read_word(uint32_t addr);
|
||||
.globl read_word
|
||||
.align 16
|
||||
read_word:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 0(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
testl $0x80000003, %ecx
|
||||
jnz rw_slow
|
||||
testb $RF_READ_BREAKPOINT, RAM_FLAGS(%ecx)
|
||||
jnz rw_special
|
||||
rw_fast:
|
||||
movl (%ecx), %eax
|
||||
ret
|
||||
rw_special:
|
||||
call read_special
|
||||
jmp rw_fast
|
||||
rw_slow:
|
||||
movl 0(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
testl $3, %ecx
|
||||
jnz rw_unaligned
|
||||
shll $10, %eax
|
||||
jc rw_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_read_word
|
||||
rw_miss:
|
||||
call read_miss
|
||||
jmp read_word
|
||||
rw_unaligned:
|
||||
call align_fault
|
||||
andl $-4, %ecx
|
||||
jmp read_word
|
||||
|
||||
// uint32_t FASTCALL read_word_ldr(uint32_t addr);
|
||||
.globl read_word_ldr
|
||||
.align 16
|
||||
read_word_ldr:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 0(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
testl $0x80000003, %ecx
|
||||
jnz rwl_slow
|
||||
testb $RF_READ_BREAKPOINT, RAM_FLAGS(%ecx)
|
||||
jnz rw_special
|
||||
movl (%ecx), %eax
|
||||
ret
|
||||
rwl_slow:
|
||||
movl 0(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
testl $3, %ecx
|
||||
jnz rwl_unaligned
|
||||
shll $10, %eax
|
||||
jc rw_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_read_word
|
||||
rwl_unaligned:
|
||||
pushl %ecx
|
||||
call rw_unaligned
|
||||
popl %ecx
|
||||
shll $3, %ecx // Unaligned ldr rotates the word so that
|
||||
rorl %cl, %eax // addressed byte ends up in low position
|
||||
ret
|
||||
|
||||
read_special:
|
||||
pushl %ecx
|
||||
pushl %ecx
|
||||
call read_action
|
||||
popl %ecx
|
||||
popl %ecx
|
||||
ret
|
||||
read_miss:
|
||||
pushl %ecx
|
||||
pushl $data_abort
|
||||
pushl $0
|
||||
pushl %ecx
|
||||
call addr_cache_miss
|
||||
addl $12, %esp
|
||||
popl %ecx
|
||||
ret
|
||||
|
||||
// void FASTCALL write_byte(uint32_t addr, uint8_t value);
|
||||
.globl write_byte
|
||||
.align 16
|
||||
write_byte:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 4(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
js wb_slow
|
||||
movl %ecx, %eax
|
||||
andl $-4, %eax
|
||||
testb $WRITE_SPECIAL_FLAGS, RAM_FLAGS(%eax)
|
||||
jnz wb_special
|
||||
wb_fast:
|
||||
movb %dl, (%ecx)
|
||||
ret
|
||||
wb_special:
|
||||
call write_special
|
||||
jmp wb_fast
|
||||
wb_slow:
|
||||
movl 4(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
shll $10, %eax
|
||||
jc wb_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_write_byte
|
||||
wb_miss:
|
||||
call write_miss
|
||||
jmp write_byte
|
||||
|
||||
// void FASTCALL write_half(uint32_t addr, uint16_t value);
|
||||
.globl write_half
|
||||
.align 16
|
||||
write_half:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 4(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
testl $0x80000001, %ecx
|
||||
jnz wh_slow
|
||||
movl %ecx, %eax
|
||||
andl $-4, %eax
|
||||
testb $WRITE_SPECIAL_FLAGS, RAM_FLAGS(%eax)
|
||||
jnz wh_special
|
||||
wh_fast:
|
||||
movw %dx, (%ecx)
|
||||
ret
|
||||
wh_special:
|
||||
call write_special
|
||||
jmp wh_fast
|
||||
wh_slow:
|
||||
movl 4(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
testl $1, %ecx
|
||||
jnz wh_unaligned
|
||||
shll $10, %eax
|
||||
jc wh_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_write_half
|
||||
wh_miss:
|
||||
call write_miss
|
||||
jmp write_half
|
||||
wh_unaligned:
|
||||
call align_fault
|
||||
decl %ecx
|
||||
jmp write_half
|
||||
|
||||
// void FASTCALL write_word(uint32_t addr, uint32_t value);
|
||||
.globl write_word
|
||||
.align 16
|
||||
write_word:
|
||||
movl %ecx, %eax
|
||||
shrl $10, %eax
|
||||
addl 4(, %eax, 8), %ecx
|
||||
AC_RELOC
|
||||
testl $0x80000003, %ecx
|
||||
jnz ww_slow
|
||||
testb $WRITE_SPECIAL_FLAGS, RAM_FLAGS(%ecx)
|
||||
jnz ww_special
|
||||
ww_fast:
|
||||
movl %edx, (%ecx)
|
||||
ret
|
||||
ww_special:
|
||||
call write_special
|
||||
jmp ww_fast
|
||||
ww_slow:
|
||||
movl 4(, %eax, 8), %eax
|
||||
AC_RELOC
|
||||
subl %eax, %ecx
|
||||
testl $3, %ecx
|
||||
jnz ww_unaligned
|
||||
shll $10, %eax
|
||||
jc ww_miss
|
||||
addl %eax, %ecx
|
||||
jmp mmio_write_word
|
||||
ww_miss:
|
||||
call write_miss
|
||||
jmp write_word
|
||||
ww_unaligned:
|
||||
call align_fault
|
||||
andl $-4, %ecx
|
||||
jmp write_word
|
||||
|
||||
write_special:
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ecx
|
||||
call write_action
|
||||
popl %ecx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
ret
|
||||
write_miss:
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl $data_abort
|
||||
pushl $1
|
||||
pushl %ecx
|
||||
call addr_cache_miss
|
||||
addl $12, %esp
|
||||
popl %ecx
|
||||
popl %edx
|
||||
ret
|
||||
|
||||
align_fault:
|
||||
testb $2, arm+ARM_CONTROL
|
||||
jz 1f
|
||||
pushl $1
|
||||
pushl %ecx
|
||||
call data_abort
|
||||
1: ret
|
||||
|
||||
.data
|
||||
.globl ac_reloc_end
|
||||
ac_reloc_end:
|
||||
@@ -1,335 +0,0 @@
|
||||
// arm_state structure offsets
|
||||
#define ARM_PC 60
|
||||
#define ARM_CPSR 64
|
||||
#define ARM_FLAG_C 70
|
||||
#define ARM_CONTROL 72
|
||||
|
||||
// translation structure offsets
|
||||
#define TRANS_JUMP_TABLE 0x08
|
||||
#define TRANS_START_PTR 0x10
|
||||
#define TRANS_END_PTR 0x18
|
||||
|
||||
// RAM_FLAGS used to have "// = MEM_MAXSIZE" at the end but the clang assembler copys the "//" into the macro, commenting out the arguments of the opcodes that use it
|
||||
#define RAM_FLAGS (80*1024*1024)
|
||||
#define RF_READ_BREAKPOINT 1
|
||||
#define RF_WRITE_BREAKPOINT 2
|
||||
#define RF_EXEC_BREAKPOINT 4
|
||||
#define RF_EXEC_DEBUG_NEXT 8
|
||||
#define RF_CODE_TRANSLATED 32
|
||||
#define RF_CODE_NO_TRANSLATE 64
|
||||
#define RF_READ_ONLY 128
|
||||
#define RF_ARMLOADER_CB 256
|
||||
#define RFS_TRANSLATION_INDEX 9
|
||||
|
||||
#define DO_READ_ACTION (RF_READ_BREAKPOINT)
|
||||
#define DO_WRITE_ACTION (RF_WRITE_BREAKPOINT | RF_CODE_TRANSLATED | RF_CODE_NO_TRANSLATE)
|
||||
|
||||
translation_enter: .global translation_enter
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
push %rbx
|
||||
push %rsi
|
||||
push %rdi
|
||||
mov %rsp, in_translation_rsp(%rip)
|
||||
|
||||
lea arm(%rip), %rbx
|
||||
mov ARM_PC(%rbx), %eax
|
||||
jmp translation_next
|
||||
|
||||
translation_next_bx: .global translation_next_bx
|
||||
testb $1, %al
|
||||
jne switch_to_thumb
|
||||
|
||||
translation_next: .global translation_next
|
||||
mov %eax, ARM_PC(%rbx)
|
||||
|
||||
lea cycle_count_delta(%rip), %r8
|
||||
cmpl $0, (%r8)
|
||||
jns return
|
||||
|
||||
lea cpu_events(%rip), %r8
|
||||
cmpl $0, (%r8)
|
||||
jnz return
|
||||
|
||||
mov ARM_PC(%rbx), %edi
|
||||
push %rdi // For 16 byte stack alignment (call pushes 8 itself)
|
||||
call read_instruction
|
||||
pop %rdi
|
||||
cmp $0, %rax
|
||||
jz return
|
||||
|
||||
addr_ok:
|
||||
movl RAM_FLAGS(%rax), %edx
|
||||
testb $RF_CODE_TRANSLATED, %dl
|
||||
jz return // Not translated
|
||||
|
||||
lea in_translation_pc_ptr(%rip), %r8
|
||||
mov %rax, (%r8)
|
||||
|
||||
shr $RFS_TRANSLATION_INDEX, %rdx
|
||||
shl $5, %rdx
|
||||
lea translation_table(%rip), %r8
|
||||
add %r8, %rdx
|
||||
|
||||
// Add one cycle for each instruction from this point to the end
|
||||
mov TRANS_END_PTR(%rdx), %rcx
|
||||
sub %rax, %rcx
|
||||
shr $2, %rcx
|
||||
lea cycle_count_delta(%rip), %r8
|
||||
add %ecx, (%r8)
|
||||
|
||||
mov %rax, %rcx
|
||||
sub TRANS_START_PTR(%rdx), %rcx
|
||||
mov TRANS_JUMP_TABLE(%rdx), %rdx
|
||||
jmp *(%rdx, %rcx, 2)
|
||||
//That is the same as
|
||||
//shr $2, %rcx
|
||||
//jmp *(%rdx, %rcx, 8)
|
||||
|
||||
return:
|
||||
lea in_translation_rsp(%rip), %r8
|
||||
movq $0, (%r8)
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
switch_to_thumb:
|
||||
dec %eax
|
||||
mov %eax, ARM_PC(%rbx)
|
||||
orb $0x20, ARM_CPSR(%rbx)
|
||||
jmp return
|
||||
|
||||
.data
|
||||
// These shift procedures are called only from translated code,
|
||||
// so they may assume that %rbx == _arm
|
||||
.align 4
|
||||
arm_shift_proc: .global arm_shift_proc
|
||||
.quad lsl
|
||||
.quad lsr
|
||||
.quad asr
|
||||
.quad 0
|
||||
.quad lsl_carry
|
||||
.quad lsr_carry
|
||||
.quad asr_carry
|
||||
.quad ror_carry
|
||||
|
||||
.text
|
||||
lsl:
|
||||
cmpb $32, %cl
|
||||
jae ls_32
|
||||
shl %cl, %eax
|
||||
ret
|
||||
|
||||
lsr:
|
||||
cmpb $32, %cl
|
||||
jae ls_32
|
||||
shr %cl, %eax
|
||||
ret
|
||||
ls_32:
|
||||
xor %eax, %eax
|
||||
ret
|
||||
|
||||
asr:
|
||||
cmpb $32, %cl
|
||||
jae asr_32
|
||||
sar %cl, %eax
|
||||
ret
|
||||
asr_32:
|
||||
sar $31, %eax
|
||||
ret
|
||||
|
||||
lsl_carry:
|
||||
cmpb $32, %cl
|
||||
jae lsl_carry_32
|
||||
testb %cl, %cl
|
||||
je lsl_carry_zero
|
||||
shl %cl, %eax
|
||||
setc ARM_FLAG_C(%rbx)
|
||||
lsl_carry_zero:
|
||||
ret
|
||||
lsl_carry_32:
|
||||
jne ls_carry_33
|
||||
shr $1, %eax
|
||||
setc ARM_FLAG_C(%rbx)
|
||||
xor %eax, %eax
|
||||
ret
|
||||
|
||||
lsr_carry:
|
||||
cmpb $32, %cl
|
||||
jae lsr_carry_32
|
||||
testb %cl, %cl
|
||||
je lsr_carry_zero
|
||||
shr %cl, %eax
|
||||
setc ARM_FLAG_C(%rbx)
|
||||
lsr_carry_zero:
|
||||
ret
|
||||
lsr_carry_32:
|
||||
jne ls_carry_33
|
||||
shl $1, %eax
|
||||
setc ARM_FLAG_C(%rbx)
|
||||
xor %eax, %eax
|
||||
ret
|
||||
ls_carry_33:
|
||||
xor %eax, %eax
|
||||
movb %al, ARM_FLAG_C(%rbx)
|
||||
ret
|
||||
|
||||
asr_carry:
|
||||
cmpb $32, %cl
|
||||
jae asr_carry_32
|
||||
testb %cl, %cl
|
||||
je asr_carry_zero
|
||||
sar %cl, %eax
|
||||
setc ARM_FLAG_C(%rbx)
|
||||
asr_carry_zero:
|
||||
ret
|
||||
asr_carry_32:
|
||||
sar $31, %eax
|
||||
sets ARM_FLAG_C(%rbx)
|
||||
ret
|
||||
|
||||
ror_carry:
|
||||
testb $31, %cl
|
||||
jz ror_carry_mult_32
|
||||
ror %cl, %eax
|
||||
setc ARM_FLAG_C(%rbx)
|
||||
ror_carry_zero:
|
||||
ret
|
||||
ror_carry_mult_32:
|
||||
testb %cl, %cl
|
||||
je ror_carry_zero
|
||||
test %eax, %eax
|
||||
sets ARM_FLAG_C(%rbx)
|
||||
ret
|
||||
|
||||
read_word_asm: .global read_word_asm
|
||||
mov %rdi, %rax
|
||||
shr $10, %rax
|
||||
shl $1, %rax
|
||||
mov addr_cache(%rip), %r8
|
||||
mov (%r8, %rax, 8), %rax
|
||||
test $3, %rax
|
||||
jnz rwa_miss
|
||||
movl (%rax, %rdi), %eax
|
||||
ret
|
||||
rwa_miss:
|
||||
push %rdx
|
||||
push %rcx
|
||||
call read_word
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
|
||||
write_word_asm: .global write_word_asm
|
||||
mov %rdi, %rax
|
||||
shr $10, %rax
|
||||
shl $1, %rax
|
||||
add $1, %rax
|
||||
mov addr_cache(%rip), %r8
|
||||
mov (%r8, %rax, 8), %rax
|
||||
test $3, %rax
|
||||
jnz wwa_miss
|
||||
movl %esi, (%rax, %rdi)
|
||||
testq $DO_WRITE_ACTION, RAM_FLAGS(%rax, %rdi)
|
||||
jnz write_action_asm
|
||||
ret
|
||||
wwa_miss:
|
||||
push %rdx
|
||||
push %rcx
|
||||
call write_word
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
|
||||
read_half_asm: .global read_half_asm
|
||||
and $-2, %rdi
|
||||
mov %rdi, %rax
|
||||
shr $10, %rax
|
||||
shl $1, %rax
|
||||
mov addr_cache(%rip), %r8
|
||||
mov (%r8, %rax, 8), %rax
|
||||
test $3, %rax
|
||||
jnz rha_miss
|
||||
movzwl (%rax, %rdi), %eax
|
||||
ret
|
||||
rha_miss:
|
||||
push %rdx
|
||||
push %rcx
|
||||
call read_half
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
|
||||
write_half_asm: .global write_half_asm
|
||||
and $-2, %rdi
|
||||
mov %rdi, %rax
|
||||
shr $10, %rax
|
||||
shl $1, %rax
|
||||
add $1, %rax
|
||||
mov addr_cache(%rip), %r8
|
||||
mov (%r8, %rax, 8), %rax
|
||||
test $3, %rax
|
||||
jnz wha_miss
|
||||
movw %si, (%rax, %rdi)
|
||||
testq $DO_WRITE_ACTION, RAM_FLAGS(%rax, %rdi)
|
||||
jnz write_action_asm
|
||||
ret
|
||||
wha_miss:
|
||||
push %rdx
|
||||
push %rcx
|
||||
call write_half
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
|
||||
read_byte_asm: .global read_byte_asm
|
||||
mov %rdi, %rax
|
||||
shr $10, %rax
|
||||
shl $1, %rax
|
||||
mov addr_cache(%rip), %r8
|
||||
mov (%r8, %rax, 8), %rax
|
||||
test $3, %rax
|
||||
jnz rba_miss
|
||||
movzb (%rax, %rdi), %rax
|
||||
ret
|
||||
rba_miss:
|
||||
push %rdx
|
||||
push %rcx
|
||||
call read_byte
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
|
||||
write_byte_asm: .global write_byte_asm
|
||||
mov %rdi, %rax
|
||||
shr $10, %rax
|
||||
shl $1, %rax
|
||||
add $1, %rax
|
||||
mov addr_cache(%rip), %r8
|
||||
mov (%r8, %rax, 8), %rax
|
||||
test $3, %rax
|
||||
jnz wba_miss
|
||||
xchg %rsi, %rdx // Can't use %rsi directly
|
||||
movb %dl, (%rax, %rdi)
|
||||
xchg %rsi, %rdx
|
||||
testq $DO_WRITE_ACTION, RAM_FLAGS(%rax, %rdi)
|
||||
jnz write_action_asm
|
||||
ret
|
||||
wba_miss:
|
||||
push %rdx
|
||||
push %rcx
|
||||
call write_byte
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
|
||||
write_action_asm:
|
||||
add %rax, %rdi
|
||||
push %rdx
|
||||
push %rcx
|
||||
call write_action
|
||||
pop %rcx
|
||||
pop %rdx
|
||||
ret
|
||||
@@ -1,170 +0,0 @@
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/cpudefs.h"
|
||||
#include "armv5te/mmu.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pxa260/pxa260.h"
|
||||
#include "pxa260/pxa260_PwrClk.h"
|
||||
}
|
||||
|
||||
|
||||
void do_cp15_mrc(uint32_t insn)
|
||||
{
|
||||
uint32_t value;
|
||||
switch (insn & 0xEF00EF) {
|
||||
case 0x000000: /* MRC p15, 0, <Rd>, c0, c0, 0: ID Code Register */
|
||||
//value = 0x41069264; /* ARM926EJ-S revision 4 */
|
||||
//value = 0x69052100;//Intel PXA260 "01101001000001010010000100000000"
|
||||
value = 0x69052D05;//Intel PXA261 "01101001000001010010110100000101"
|
||||
break;
|
||||
case 0x000010: /* MRC p15, 0, <Rd>, c0, c0, 1: Cache Type Register */
|
||||
value = 0x1D112152; /* ICache: 16KB 4-way 8 word, DCache: 8KB 4-way 8 word */
|
||||
break;
|
||||
case 0x000020: /* MRC p15, 0, <Rd>, c0, c0, 2: TCM Status Register */
|
||||
value = 0;
|
||||
break;
|
||||
case 0x010000: /* MRC p15, 0, <Rd>, c1, c0, 0: Control Register */
|
||||
value = arm.control;
|
||||
break;
|
||||
case 0x020000: /* MRC p15, 0, <Rd>, c2, c0, 0: Translation Table Base Register */
|
||||
value = arm.translation_table_base;
|
||||
break;
|
||||
case 0x030000: /* MRC p15, 0, <Rd>, c3, c0, 0: Domain Access Control Register */
|
||||
value = arm.domain_access_control;
|
||||
break;
|
||||
case 0x050000: /* MRC p15, 0, <Rd>, c5, c0, 0: Data Fault Status Register */
|
||||
value = arm.data_fault_status;
|
||||
break;
|
||||
case 0x050020: /* MRC p15, 0, <Rd>, c5, c0, 1: Instruction Fault Status Register */
|
||||
value = arm.instruction_fault_status;
|
||||
break;
|
||||
case 0x060000: /* MRC p15, 0, <Rd>, c6, c0, 0: Fault Address Register */
|
||||
value = arm.fault_address;
|
||||
break;
|
||||
case 0x07006A: /* MRC p15, 0, <Rd>, c7, c10, 3: Test and clean DCache */
|
||||
value = 1 << 30;
|
||||
break;
|
||||
case 0x07006E: /* MRC p15, 0, <Rd>, c7, c14, 3: Test, clean, and invalidate DCache */
|
||||
value = 1 << 30;
|
||||
break;
|
||||
case 0x0D0000: /* MRC p15, 0, <Rd>, c13, c0, 0: Read FCSE PID */
|
||||
value = 0;
|
||||
break;
|
||||
case 0x0F0000: /* MRC p15, 0, <Rd>, c15, c0, 0: Debug Override Register */
|
||||
// Unimplemented
|
||||
value = 0;
|
||||
break;
|
||||
case 0x0F0001: /* MRC p15, 0, <Rd>, c15, c1, 0: Unknown */
|
||||
//TODO: Unknown(implmentation defined cp15 register)
|
||||
value = 0;
|
||||
break;
|
||||
default:
|
||||
warn("Unknown coprocessor instruction MRC %08X", insn);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
if ((insn >> 12 & 15) == 15) {
|
||||
arm.cpsr_n = value >> 31 & 1;
|
||||
arm.cpsr_z = value >> 30 & 1;
|
||||
arm.cpsr_c = value >> 29 & 1;
|
||||
arm.cpsr_v = value >> 28 & 1;
|
||||
} else
|
||||
arm.reg[insn >> 12 & 15] = value;
|
||||
}
|
||||
|
||||
void do_cp15_mcr(uint32_t insn)
|
||||
{
|
||||
uint32_t value = reg(insn >> 12 & 15);
|
||||
switch (insn & 0xEF00EF) {
|
||||
case 0x010000: { /* MCR p15, 0, <Rd>, c1, c0, 0: Control Register */
|
||||
uint32_t change = value ^ arm.control;
|
||||
//TODO: actually implement this register fully
|
||||
/*
|
||||
if ((value & 0xFFFF8CF0) != 0x00050070)
|
||||
error("Bad or unimplemented control register value: %x (unsupported: %x)\n", value, (value & 0xFFFF8CF8) ^ 0x00050078);
|
||||
*/
|
||||
arm.control = value;
|
||||
if (change & 1){
|
||||
// MMU is being turned on or off
|
||||
addr_cache_flush();
|
||||
emuprintf("Turned MMU %s\n", value & 1 ? "on" : "off");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x020000: /* MCR p15, 0, <Rd>, c2, c0, 0: Translation Table Base Register */
|
||||
arm.translation_table_base = value & ~0x3FFF;
|
||||
addr_cache_flush();
|
||||
break;
|
||||
case 0x030000: /* MCR p15, 0, <Rd>, c3, c0, 0: Domain Access Control Register */
|
||||
arm.domain_access_control = value;
|
||||
addr_cache_flush();
|
||||
break;
|
||||
case 0x050000: /* MCR p15, 0, <Rd>, c5, c0, 0: Data Fault Status Register */
|
||||
arm.data_fault_status = value;
|
||||
break;
|
||||
case 0x050020: /* MCR p15, 0, <Rd>, c5, c0, 1: Instruction Fault Status Register */
|
||||
arm.instruction_fault_status = value;
|
||||
break;
|
||||
case 0x060000: /* MCR p15, 0, <Rd>, c6, c0, 0: Fault Address Register */
|
||||
arm.fault_address = value;
|
||||
break;
|
||||
case 0x070080: /* MCR p15, 0, <Rd>, c7, c0, 4: Wait for interrupt */
|
||||
emuprintf("Wait for interrupt, does not work with uARM core!\n");
|
||||
cycle_count_delta = 0;
|
||||
if (arm.interrupts == 0) {
|
||||
arm.reg[15] -= 4;
|
||||
cpu_events |= EVENT_WAITING;
|
||||
}
|
||||
break;
|
||||
case 0x080005: /* MCR p15, 0, <Rd>, c8, c5, 0: Invalidate instruction TLB */
|
||||
case 0x080007: /* MCR p15, 0, <Rd>, c8, c7, 0: Invalidate TLB */
|
||||
case 0x080025: /* MCR p15, 0, <Rd>, c8, c5, 1: Invalidate instruction TLB entry */
|
||||
case 0x080027: /* MCR p15, 0, <Rd>, c8, c7, 1: Invalidate TLB (used by polydumper) */
|
||||
case 0x070005: /* MCR p15, 0, <Rd>, c7, c5, 0: Invalidate ICache */
|
||||
case 0x070025: /* MCR p15, 0, <Rd>, c7, c5, 1: Invalidate ICache line */
|
||||
case 0x070007: /* MCR p15, 0, <Rd>, c7, c7, 0: Invalidate ICache and DCache */
|
||||
addr_cache_flush();
|
||||
break;
|
||||
|
||||
case 0x080006: /* MCR p15, 0, <Rd>, c8, c6, 0: Invalidate data TLB */
|
||||
case 0x080026: /* MCR p15, 0, <Rd>, c8, c6, 1: Invalidate data TLB entry */
|
||||
case 0x070026: /* MCR p15, 0, <Rd>, c7, c6, 1: Invalidate single DCache entry */
|
||||
case 0x07002A: /* MCR p15, 0, <Rd>, c7, c10, 1: Clean DCache line */
|
||||
case 0x07002E: /* MCR p15, 0, <Rd>, c7, c14, 1: Clean and invalidate single DCache entry */
|
||||
case 0x07008A: /* MCR p15, 0, <Rd>, c7, c10, 4: Drain write buffer */
|
||||
case 0x0F0000: /* MCR p15, 0, <Rd>, c15, c0, 0: Debug Override Register */
|
||||
#ifdef SUPPORT_LINUX
|
||||
// Normally ignored, but somehow needed for linux to boot correctly
|
||||
addr_cache_flush();
|
||||
#endif
|
||||
break;
|
||||
case 0x0F0001: /* MCR p15, 0, <Rd>, c15, c1, 0: Unknown */
|
||||
//TODO: Unknown(implmentation defined cp15 register)
|
||||
break;
|
||||
default:
|
||||
warn("Unknown coprocessor instruction MCR %08X\n", insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void do_cp15_instruction(Instruction i)
|
||||
{
|
||||
uint32_t insn = i.raw;
|
||||
if(insn & 0x00100000)
|
||||
return do_cp15_mrc(insn);
|
||||
else
|
||||
return do_cp15_mcr(insn);
|
||||
}
|
||||
|
||||
void do_cp14_instruction(Instruction i)
|
||||
{
|
||||
uint32_t instr = i.raw;
|
||||
bool specialInstr = i.cond == 0xF;
|
||||
bool success;
|
||||
|
||||
success = pxa260pwrClkPrvCoprocRegXferFunc(&pxa260PwrClk, specialInstr, (instr & 0x00100000) != 0, (instr >> 21) & 0x07, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07);
|
||||
|
||||
if(!success)
|
||||
warn("Unknown coprocessor instruction MCR %08X\n", instr);
|
||||
}
|
||||
|
||||
@@ -1,428 +0,0 @@
|
||||
#include <algorithm>
|
||||
//#include <mutex>
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
// Uncomment the following line to measure the time until the OS is loaded
|
||||
// #define BENCHMARK
|
||||
#ifdef BENCHMARK
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "armv5te/armsnippets.h"
|
||||
#include "armv5te/asmcode.h"
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/cpudefs.h"
|
||||
#include "armv5te/debug.h"
|
||||
#include "armv5te/emu.h"
|
||||
#include "armv5te/mem.h"
|
||||
#include "armv5te/mmu.h"
|
||||
#include "armv5te/translate.h"
|
||||
|
||||
// Global CPU state
|
||||
struct arm_state arm;
|
||||
|
||||
void cpu_arm_loop()
|
||||
{
|
||||
while (!exiting && cycle_count_delta < 0 && current_instr_size == 4)
|
||||
{
|
||||
arm.reg[15] &= ~0x3; // Align PC
|
||||
Instruction *p = static_cast<Instruction*>(read_instruction(arm.reg[15]));
|
||||
|
||||
#ifdef BENCHMARK
|
||||
static clock_t start = 0;
|
||||
if(arm.reg[15] == 0)
|
||||
{
|
||||
start = clock();
|
||||
turbo_mode = true;
|
||||
}
|
||||
else if(arm.reg[15] == 0x10000000 || arm.reg[15] == 0x11800000)
|
||||
{
|
||||
clock_t diff = clock() - start;
|
||||
printf("%ld ms\n", diff / 1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t *flags_ptr = &RAM_FLAGS(p);
|
||||
|
||||
// Check for pending events
|
||||
if(cpu_events)
|
||||
{
|
||||
// Events other than DEBUG_STEP are handled outside
|
||||
if(cpu_events & ~EVENT_DEBUG_STEP)
|
||||
break;
|
||||
goto enter_debugger;
|
||||
}
|
||||
|
||||
// TODO: Other flags
|
||||
if(*flags_ptr & (RF_EXEC_BREAKPOINT | RF_EXEC_DEBUG_NEXT | RF_ARMLOADER_CB))
|
||||
{
|
||||
if(*flags_ptr & RF_ARMLOADER_CB)
|
||||
{
|
||||
*flags_ptr &= ~RF_ARMLOADER_CB;
|
||||
armloader_cb();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*flags_ptr & RF_EXEC_BREAKPOINT)
|
||||
gui_debug_printf("Breakpoint at 0x%08X\n", arm.reg[15]);
|
||||
enter_debugger:
|
||||
uint32_t pc = arm.reg[15];
|
||||
debugger(DBG_EXEC_BREAKPOINT, 0);
|
||||
if(arm.reg[15] != pc)
|
||||
continue; // Debugger changed PC
|
||||
}
|
||||
}
|
||||
#ifndef NO_TRANSLATION
|
||||
else if(do_translate && !(*flags_ptr & DONT_TRANSLATE) && (*flags_ptr & RF_CODE_EXECUTED))
|
||||
translate(arm.reg[15], &p->raw);
|
||||
|
||||
// If the instruction is translated, use the translation
|
||||
if((~cpu_events & EVENT_DEBUG_STEP) && *flags_ptr & RF_CODE_TRANSLATED)
|
||||
{
|
||||
#if TRANSLATION_ENTER_HAS_PTR
|
||||
translation_enter(p);
|
||||
#else
|
||||
translation_enter();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
*flags_ptr |= RF_CODE_EXECUTED;
|
||||
#endif
|
||||
|
||||
/*
|
||||
//TODO: remove this, causes slowdown
|
||||
if(arm.reg[15] == 0x200AC088)
|
||||
emuprintf("HAL state set:%d\n", arm.reg[0]);
|
||||
*/
|
||||
|
||||
arm.reg[15] += 4; // Increment now to account for the pipeline
|
||||
++cycle_count_delta;
|
||||
do_arm_instruction(*p);
|
||||
}
|
||||
}
|
||||
|
||||
// Makes arm.reg[15] point to the current instruction
|
||||
void fix_pc_for_fault()
|
||||
{
|
||||
#ifndef NO_TRANSLATION
|
||||
translate_fix_pc();
|
||||
#endif
|
||||
|
||||
arm.reg[15] -= current_instr_size;
|
||||
}
|
||||
|
||||
void prefetch_abort(uint32_t mva, uint8_t status)
|
||||
{
|
||||
warn("Prefetch abort: address=%08X status=%02X\n", mva, status);
|
||||
arm.reg[15] += 4;
|
||||
// Fault address register not changed
|
||||
arm.instruction_fault_status = status;
|
||||
cpu_exception(EX_PREFETCH_ABORT);
|
||||
if (mva == arm.reg[15])
|
||||
error("Abort occurred with exception vectors unmapped");
|
||||
longjmp(restart_after_exception, 1);
|
||||
}
|
||||
|
||||
void data_abort(uint32_t mva, uint8_t status)
|
||||
{
|
||||
fix_pc_for_fault();
|
||||
warn("Data abort: address=%08X status=%02X instruction at %08X\n", mva, status, arm.reg[15]);
|
||||
arm.reg[15] += 8;
|
||||
arm.fault_address = mva;
|
||||
arm.data_fault_status = status;
|
||||
cpu_exception(EX_DATA_ABORT);
|
||||
longjmp(restart_after_exception, 1);
|
||||
}
|
||||
|
||||
void undefined_instruction()
|
||||
{
|
||||
fix_pc_for_fault();
|
||||
if(current_instr_size == 4)
|
||||
warn("Undefined instruction 0x%08X at 0x%08X\n", read_word(arm.reg[15]), arm.reg[15]);
|
||||
else
|
||||
warn("Undefined instruction 0x%04X at 0x%08X\n", read_half(arm.reg[15]), arm.reg[15]);
|
||||
arm.reg[15] += current_instr_size;
|
||||
cpu_exception(EX_UNDEFINED);
|
||||
longjmp(restart_after_exception, 1);
|
||||
}
|
||||
|
||||
void *try_ptr(uint32_t addr)
|
||||
{
|
||||
//There are two different addr_cache formats...
|
||||
#ifdef AC_FLAGS
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
|
||||
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID)
|
||||
return addr_cache_miss(addr, false, nullptr);
|
||||
else // MMIO stuff
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
return (void*)entry;
|
||||
#else
|
||||
void *ptr = &addr_cache[(addr >> 10) << 1][addr];
|
||||
if(unlikely((uintptr_t)ptr & AC_NOT_PTR))
|
||||
ptr = addr_cache_miss(addr, false, nullptr);
|
||||
|
||||
return ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void * FASTCALL read_instruction(uint32_t addr)
|
||||
{
|
||||
//There are two different addr_cache formats...
|
||||
#ifdef AC_FLAGS
|
||||
uintptr_t entry = *(uintptr_t*)(addr_cache + ((addr >> 10) << 1));
|
||||
|
||||
if(unlikely(entry & AC_FLAGS))
|
||||
{
|
||||
if(entry & AC_INVALID)
|
||||
return addr_cache_miss(addr, false, prefetch_abort);
|
||||
else // Executing MMIO stuff
|
||||
error("PC in MMIO range: 0x%x\n", addr);
|
||||
}
|
||||
|
||||
entry += addr;
|
||||
return (void*)entry;
|
||||
#else
|
||||
void *ptr = &addr_cache[(addr >> 10) << 1][addr];
|
||||
if(unlikely((uintptr_t)ptr & AC_NOT_PTR))
|
||||
{
|
||||
ptr = addr_cache_miss(addr, false, prefetch_abort);
|
||||
if (!ptr)
|
||||
error("Bad PC: %08X\n", addr);
|
||||
}
|
||||
return ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Update cpu_events
|
||||
void cpu_int_check()
|
||||
{
|
||||
//events arnt threaded like this in Mu, plus this breaks the RetroArch build, some undefined reference thing
|
||||
//static std::mutex mut;
|
||||
//std::lock_guard<std::mutex> lg(mut);
|
||||
|
||||
if (arm.interrupts & ~arm.cpsr_low28 & 0x80)
|
||||
cpu_events |= EVENT_IRQ;
|
||||
else
|
||||
cpu_events &= ~EVENT_IRQ;
|
||||
|
||||
if (arm.interrupts & ~arm.cpsr_low28 & 0x40)
|
||||
cpu_events |= EVENT_FIQ;
|
||||
else
|
||||
cpu_events &= ~EVENT_FIQ;
|
||||
}
|
||||
|
||||
static const constexpr uint8_t exc_flags[] = {
|
||||
MODE_SVC | 0xC0, /* Reset */
|
||||
MODE_UND | 0x80, /* Undefined instruction */
|
||||
MODE_SVC | 0x80, /* Software interrupt */
|
||||
MODE_ABT | 0x80, /* Prefetch abort */
|
||||
MODE_ABT | 0x80, /* Data abort */
|
||||
0, /* Reserved */
|
||||
MODE_IRQ | 0x80, /* IRQ */
|
||||
MODE_FIQ | 0xC0, /* FIQ */
|
||||
};
|
||||
|
||||
void cpu_exception(int type)
|
||||
{
|
||||
/* Switch mode, disable interrupts */
|
||||
uint32_t old_cpsr = get_cpsr();
|
||||
set_cpsr_full((old_cpsr & ~0x3F) | exc_flags[type]);
|
||||
*ptr_spsr() = old_cpsr;
|
||||
|
||||
/* Branch-and-link to exception handler */
|
||||
arm.reg[14] = arm.reg[15];
|
||||
arm.reg[15] = type << 2;
|
||||
if (arm.control & 0x2000) /* High vectors */
|
||||
arm.reg[15] += 0xFFFF0000;
|
||||
}
|
||||
|
||||
uint32_t get_cpsr_flags()
|
||||
{
|
||||
return arm.cpsr_n << 31
|
||||
| arm.cpsr_z << 30
|
||||
| arm.cpsr_c << 29
|
||||
| arm.cpsr_v << 28;
|
||||
}
|
||||
|
||||
void set_cpsr_flags(uint32_t flags)
|
||||
{
|
||||
arm.cpsr_n = (flags >> 31) & 1;
|
||||
arm.cpsr_z = (flags >> 30) & 1;
|
||||
arm.cpsr_c = (flags >> 29) & 1;
|
||||
arm.cpsr_v = (flags >> 28) & 1;
|
||||
}
|
||||
|
||||
// Get full CPSR register
|
||||
uint32_t get_cpsr()
|
||||
{
|
||||
return arm.cpsr_n << 31
|
||||
| arm.cpsr_z << 30
|
||||
| arm.cpsr_c << 29
|
||||
| arm.cpsr_v << 28
|
||||
| arm.cpsr_low28;
|
||||
}
|
||||
|
||||
void set_cpsr_full(uint32_t cpsr)
|
||||
{
|
||||
uint8_t old_mode = arm.cpsr_low28 & 0x1F,
|
||||
new_mode = cpsr & 0x1F;
|
||||
|
||||
if(old_mode == new_mode)
|
||||
goto same_mode;
|
||||
|
||||
// Only FIQ mode has more than 2 regs banked
|
||||
if(old_mode == MODE_FIQ)
|
||||
std::copy(arm.reg + 8, arm.reg + 13, arm.r8_fiq);
|
||||
else
|
||||
std::copy(arm.reg + 8, arm.reg + 13, arm.r8_usr);
|
||||
|
||||
switch(old_mode)
|
||||
{
|
||||
case MODE_USR: case MODE_SYS:
|
||||
std::copy(arm.reg + 13, arm.reg + 15, arm.r13_usr);
|
||||
break;
|
||||
case MODE_FIQ:
|
||||
std::copy(arm.reg + 13, arm.reg + 15, arm.r13_fiq);
|
||||
break;
|
||||
case MODE_IRQ:
|
||||
std::copy(arm.reg + 13, arm.reg + 15, arm.r13_irq);
|
||||
break;
|
||||
case MODE_SVC:
|
||||
std::copy(arm.reg + 13, arm.reg + 15, arm.r13_svc);
|
||||
break;
|
||||
case MODE_ABT:
|
||||
std::copy(arm.reg + 13, arm.reg + 15, arm.r13_abt);
|
||||
break;
|
||||
case MODE_UND:
|
||||
std::copy(arm.reg + 13, arm.reg + 15, arm.r13_und);
|
||||
break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
if(new_mode == MODE_FIQ)
|
||||
std::copy(arm.r8_fiq, arm.r8_fiq + 5, arm.reg + 8);
|
||||
else
|
||||
std::copy(arm.r8_usr, arm.r8_usr + 5, arm.reg + 8);
|
||||
|
||||
switch(new_mode)
|
||||
{
|
||||
case MODE_USR: case MODE_SYS:
|
||||
std::copy(arm.r13_usr, arm.r13_usr + 2, arm.reg + 13);
|
||||
break;
|
||||
case MODE_FIQ:
|
||||
std::copy(arm.r13_fiq, arm.r13_fiq + 2, arm.reg + 13);
|
||||
break;
|
||||
case MODE_IRQ:
|
||||
std::copy(arm.r13_irq, arm.r13_irq + 2, arm.reg + 13);
|
||||
break;
|
||||
case MODE_SVC:
|
||||
std::copy(arm.r13_svc, arm.r13_svc + 2, arm.reg + 13);
|
||||
break;
|
||||
case MODE_ABT:
|
||||
std::copy(arm.r13_abt, arm.r13_abt + 2, arm.reg + 13);
|
||||
break;
|
||||
case MODE_UND:
|
||||
std::copy(arm.r13_und, arm.r13_und + 2, arm.reg + 13);
|
||||
break;
|
||||
default: error("Invalid mode 0x%x\n", new_mode);
|
||||
}
|
||||
|
||||
// Access permissions are different
|
||||
if((old_mode == MODE_USR) ^ (new_mode == MODE_USR))
|
||||
addr_cache_flush();
|
||||
|
||||
same_mode:
|
||||
if(cpsr & 0x01000000)
|
||||
error("Jazelle not implemented!");
|
||||
|
||||
arm.cpsr_n = (cpsr >> 31) & 1;
|
||||
arm.cpsr_z = (cpsr >> 30) & 1;
|
||||
arm.cpsr_c = (cpsr >> 29) & 1;
|
||||
arm.cpsr_v = (cpsr >> 28) & 1;
|
||||
arm.cpsr_low28 = cpsr & 0x090000FF; // Mask off reserved bits
|
||||
cpu_int_check();
|
||||
}
|
||||
|
||||
void FASTCALL set_cpsr(uint32_t cpsr, uint32_t mask) {
|
||||
if (!(arm.cpsr_low28 & 0x0F)) {
|
||||
/* User mode. Don't change privileged or execution state bits */
|
||||
mask &= ~0x010000FF;
|
||||
}
|
||||
cpsr = (cpsr & mask) | (get_cpsr() & ~mask);
|
||||
if (cpsr & 0x20)
|
||||
error("Cannot set T bit with MSR instruction");
|
||||
set_cpsr_full(cpsr);
|
||||
}
|
||||
|
||||
uint32_t *ptr_spsr()
|
||||
{
|
||||
switch (arm.cpsr_low28 & 0x1F)
|
||||
{
|
||||
case MODE_FIQ: return &arm.spsr_fiq;
|
||||
case MODE_IRQ: return &arm.spsr_irq;
|
||||
case MODE_SVC: return &arm.spsr_svc;
|
||||
case MODE_ABT: return &arm.spsr_abt;
|
||||
case MODE_UND: return &arm.spsr_und;
|
||||
}
|
||||
error("Attempted to access SPSR from user or system mode");
|
||||
}
|
||||
|
||||
uint32_t get_spsr() {
|
||||
return *ptr_spsr();
|
||||
}
|
||||
|
||||
void FASTCALL set_spsr(uint32_t spsr, uint32_t mask) {
|
||||
*ptr_spsr() ^= (*ptr_spsr() ^ spsr) & mask;
|
||||
}
|
||||
|
||||
uint32_t reg(uint8_t i)
|
||||
{
|
||||
if(unlikely(i == 15))
|
||||
error("PC invalid in this context!\n");
|
||||
return arm.reg[i];
|
||||
}
|
||||
|
||||
uint32_t reg_pc(uint8_t i)
|
||||
{
|
||||
if(unlikely(i == 15))
|
||||
return arm.reg[15] + 4;
|
||||
return arm.reg[i];
|
||||
}
|
||||
|
||||
uint32_t reg_pc_mem(uint8_t i)
|
||||
{
|
||||
if(unlikely(i == 15))
|
||||
return arm.reg[15] + 8;
|
||||
return arm.reg[i];
|
||||
}
|
||||
|
||||
void set_reg(uint8_t i, uint32_t value)
|
||||
{
|
||||
if(unlikely(i == 15))
|
||||
error("PC invalid in this context!\n");
|
||||
arm.reg[i] = value;
|
||||
}
|
||||
|
||||
void set_reg_pc(uint8_t i, uint32_t value)
|
||||
{
|
||||
arm.reg[i] = value;
|
||||
}
|
||||
|
||||
void set_reg_bx(uint8_t i, uint32_t value)
|
||||
{
|
||||
arm.reg[i] = value;
|
||||
|
||||
if(i == 15 && (value & 1))
|
||||
{
|
||||
arm.cpsr_low28 |= 0x20; // Enter Thumb mode
|
||||
arm.reg[15] -= 1;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/mem.h"
|
||||
#include "armv5te/emu.h"
|
||||
|
||||
|
||||
/* cycle_count_delta is a (usually negative) number telling what the time is relative
|
||||
* to the next scheduled event. See sched.c */
|
||||
int cycle_count_delta;
|
||||
|
||||
bool exiting;
|
||||
bool do_translate;
|
||||
|
||||
jmp_buf restart_after_exception;
|
||||
|
||||
uint32_t cpu_events;
|
||||
@@ -1,143 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "armv5te/emu.h"
|
||||
#include "armv5te/os/os.h"
|
||||
#include "armv5te/mem.h"
|
||||
#include "armv5te/translate.h"
|
||||
|
||||
uint8_t (*read_byte_map[64])(uint32_t addr);
|
||||
uint16_t (*read_half_map[64])(uint32_t addr);
|
||||
uint32_t (*read_word_map[64])(uint32_t addr);
|
||||
void (*write_byte_map[64])(uint32_t addr, uint8_t value);
|
||||
void (*write_half_map[64])(uint32_t addr, uint16_t value);
|
||||
void (*write_word_map[64])(uint32_t addr, uint32_t value);
|
||||
|
||||
/* For invalid/unknown physical addresses */
|
||||
uint8_t bad_read_byte(uint32_t addr) { warn("Bad read_byte: %08X", addr); return 0; }
|
||||
uint16_t bad_read_half(uint32_t addr) { warn("Bad read_half: %08X", addr); return 0; }
|
||||
uint32_t bad_read_word(uint32_t addr) { warn("Bad read_word: %08X", addr); return 0; }
|
||||
void bad_write_byte(uint32_t addr, uint8_t value) { warn("Bad write_byte: %08X %02X", addr, value); }
|
||||
void bad_write_half(uint32_t addr, uint16_t value) { warn("Bad write_half: %08X %04X", addr, value); }
|
||||
void bad_write_word(uint32_t addr, uint32_t value) { warn("Bad write_word: %08X %08X", addr, value); }
|
||||
|
||||
uint8_t *mem_and_flags = NULL;
|
||||
struct mem_area_desc mem_areas[2];
|
||||
|
||||
void *phys_mem_ptr(uint32_t addr, uint32_t size) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(mem_areas)/sizeof(*mem_areas); i++) {
|
||||
uint32_t offset = addr - mem_areas[i].base;
|
||||
if (offset < mem_areas[i].size && size <= mem_areas[i].size - offset)
|
||||
return mem_areas[i].ptr + offset;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t phys_mem_addr(void *ptr) {
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
uint32_t offset = (uint8_t *)ptr - mem_areas[i].ptr;
|
||||
if (offset < mem_areas[i].size)
|
||||
return mem_areas[i].base + offset;
|
||||
}
|
||||
return -1; // should never happen
|
||||
}
|
||||
|
||||
void read_action(void *ptr) {
|
||||
// this is just debugging stuff
|
||||
/*
|
||||
uint32_t addr = phys_mem_addr(ptr);
|
||||
if (!gdb_connected)
|
||||
emuprintf("Hit read breakpoint at %08X. Entering debugger.\n", addr);
|
||||
debugger(DBG_READ_BREAKPOINT, addr);
|
||||
*/
|
||||
}
|
||||
|
||||
void write_action(void *ptr) {
|
||||
// this is just debugging stuff
|
||||
uint32_t addr = phys_mem_addr(ptr);
|
||||
uint32_t *flags = &RAM_FLAGS((size_t)ptr & ~3);
|
||||
/*
|
||||
// this is just debugging stuff
|
||||
if (*flags & RF_WRITE_BREAKPOINT) {
|
||||
if (!gdb_connected)
|
||||
emuprintf("Hit write breakpoint at %08X. Entering debugger.\n", addr);
|
||||
debugger(DBG_WRITE_BREAKPOINT, addr);
|
||||
}
|
||||
*/
|
||||
#ifndef NO_TRANSLATION
|
||||
if (*flags & RF_CODE_TRANSLATED) {
|
||||
logprintf(LOG_CPU, "Wrote to translated code at %08X. Deleting translations.\n", addr);
|
||||
invalidate_translation(*flags >> RFS_TRANSLATION_INDEX);
|
||||
} else {
|
||||
*flags &= ~RF_CODE_NO_TRANSLATE;
|
||||
}
|
||||
*flags &= ~RF_CODE_EXECUTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 00000000, 10000000, A4000000: ROM and RAM */
|
||||
uint8_t memory_read_byte(uint32_t addr) {
|
||||
uint8_t *ptr = phys_mem_ptr(addr, 1);
|
||||
if (!ptr) return bad_read_byte(addr);
|
||||
if (RAM_FLAGS((size_t)ptr & ~3) & DO_READ_ACTION) read_action(ptr);
|
||||
return *ptr;
|
||||
}
|
||||
uint16_t memory_read_half(uint32_t addr) {
|
||||
uint16_t *ptr = phys_mem_ptr(addr, 2);
|
||||
if (!ptr) return bad_read_half(addr);
|
||||
if (RAM_FLAGS((size_t)ptr & ~3) & DO_READ_ACTION) read_action(ptr);
|
||||
return *ptr;
|
||||
}
|
||||
uint32_t memory_read_word(uint32_t addr) {
|
||||
uint32_t *ptr = phys_mem_ptr(addr, 4);
|
||||
if (!ptr) return bad_read_word(addr);
|
||||
if (RAM_FLAGS(ptr) & DO_READ_ACTION) read_action(ptr);
|
||||
return *ptr;
|
||||
}
|
||||
void memory_write_byte(uint32_t addr, uint8_t value) {
|
||||
uint8_t *ptr = phys_mem_ptr(addr, 1);
|
||||
if (!ptr) { bad_write_byte(addr, value); return; }
|
||||
uint32_t flags = RAM_FLAGS((size_t)ptr & ~3);
|
||||
if (flags & RF_READ_ONLY) { bad_write_byte(addr, value); return; }
|
||||
if (flags & DO_WRITE_ACTION) write_action(ptr);
|
||||
*ptr = value;
|
||||
}
|
||||
void memory_write_half(uint32_t addr, uint16_t value) {
|
||||
uint16_t *ptr = phys_mem_ptr(addr, 2);
|
||||
if (!ptr) { bad_write_half(addr, value); return; }
|
||||
uint32_t flags = RAM_FLAGS((size_t)ptr & ~3);
|
||||
if (flags & RF_READ_ONLY) { bad_write_half(addr, value); return; }
|
||||
if (flags & DO_WRITE_ACTION) write_action(ptr);
|
||||
*ptr = value;
|
||||
}
|
||||
void memory_write_word(uint32_t addr, uint32_t value) {
|
||||
uint32_t *ptr = phys_mem_ptr(addr, 4);
|
||||
if (!ptr) { bad_write_word(addr, value); return; }
|
||||
uint32_t flags = RAM_FLAGS(ptr);
|
||||
if (flags & RF_READ_ONLY) { bad_write_word(addr, value); return; }
|
||||
if (flags & DO_WRITE_ACTION) write_action(ptr);
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
uint32_t FASTCALL mmio_read_byte(uint32_t addr) {
|
||||
return read_byte_map[addr >> 26](addr);
|
||||
}
|
||||
uint32_t FASTCALL mmio_read_half(uint32_t addr) {
|
||||
return read_half_map[addr >> 26](addr);
|
||||
}
|
||||
uint32_t FASTCALL mmio_read_word(uint32_t addr) {
|
||||
return read_word_map[addr >> 26](addr);
|
||||
}
|
||||
void FASTCALL mmio_write_byte(uint32_t addr, uint32_t value) {
|
||||
write_byte_map[addr >> 26](addr, value);
|
||||
}
|
||||
void FASTCALL mmio_write_half(uint32_t addr, uint32_t value) {
|
||||
write_half_map[addr >> 26](addr, value);
|
||||
}
|
||||
void FASTCALL mmio_write_word(uint32_t addr, uint32_t value) {
|
||||
write_word_map[addr >> 26](addr, value);
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "armv5te/translate.h"
|
||||
#include "armv5te/emu.h"
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/mmu.h"
|
||||
#include "armv5te/mem.h"
|
||||
#include "armv5te/os/os.h"
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
#include "armv5te/uArm/CPU_2.h"
|
||||
#include "armv5te/uArm/icache.h"
|
||||
#include "pxa260/pxa260.h"
|
||||
#endif
|
||||
|
||||
/* Copy of translation table in memory (hack to approximate effect of having a TLB) */
|
||||
static uint32_t mmu_translation_table[0x1000];
|
||||
|
||||
void mmu_dump_tables(void) {
|
||||
if ((arm.control & 1) == 0) {
|
||||
gui_debug_printf("MMU disabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gui_debug_printf("MMU translations:\n");
|
||||
uint32_t *tt = (uint32_t*)phys_mem_ptr(arm.translation_table_base, 0x4000);
|
||||
if (!tt) {
|
||||
gui_debug_printf("TTB points to invalid memory, using TLB\n");
|
||||
tt = mmu_translation_table;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x1000; i++) {
|
||||
uint32_t tt_entry = tt[i];
|
||||
uint32_t virt_addr = i << 20;
|
||||
uint32_t virt_shift = 0;
|
||||
uint32_t *l1_table = NULL;
|
||||
uint32_t l1_table_size = 0;;
|
||||
uint32_t l1_entry;
|
||||
uint32_t j = 0;
|
||||
uint32_t page_size = 0;
|
||||
char *page_type = "?";
|
||||
if (!(tt_entry & 3))
|
||||
continue; // Invalid
|
||||
if ((tt_entry & 3) == 2) { // Section (1MB)
|
||||
page_size = 0x100000;
|
||||
page_type = "1mB";
|
||||
l1_entry = tt_entry;
|
||||
j = 0;
|
||||
goto section;
|
||||
} else if ((tt_entry & 3) == 1) { // Coarse page table
|
||||
l1_table = phys_mem_ptr(tt_entry & 0xFFFFFC00, 0x400);
|
||||
l1_table_size = 256;
|
||||
virt_shift = 12;
|
||||
} else if ((tt_entry & 3) == 3) { // Fine page table
|
||||
l1_table = phys_mem_ptr(tt_entry & 0xFFFFF000, 0x1000);
|
||||
l1_table_size = 1024;
|
||||
virt_shift = 10;
|
||||
}
|
||||
|
||||
for (j = 0; j < l1_table_size; j++) {
|
||||
l1_entry = l1_table[j];
|
||||
if (!(l1_entry & 3))
|
||||
continue; // Invalid
|
||||
if ((l1_entry & 3) == 1) { // Large page (64kB)
|
||||
page_size = 0x10000;
|
||||
page_type = "64kB";
|
||||
}
|
||||
else if ((l1_entry & 3) == 2) { // Small page (4kB)
|
||||
page_size = 0x1000;
|
||||
page_type = "4kB";
|
||||
}
|
||||
else if ((l1_entry & 3) == 3) { // Tiny page (1kB)
|
||||
page_size = 0x400;
|
||||
page_type = "1kB";
|
||||
}
|
||||
section:;
|
||||
gui_debug_printf("%08X -> %08X (%s) (0x%8x)\n", virt_addr + j * (1 << virt_shift), l1_entry & -page_size, page_type, l1_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Translate a virtual address to a physical address */
|
||||
uint32_t mmu_translate(uint32_t addr, bool writing, fault_proc *fault, uint8_t *s_status) {
|
||||
uint32_t page_size;
|
||||
if (!(arm.control & 1))
|
||||
return addr;
|
||||
|
||||
uint32_t *table = mmu_translation_table;
|
||||
uint32_t entry = table[addr >> 20];
|
||||
uint32_t domain = entry >> 5 & 0x0F;
|
||||
uint32_t status = domain << 4;
|
||||
uint32_t ap;
|
||||
|
||||
switch (entry & 3) {
|
||||
default: /* Invalid */
|
||||
if (s_status) *s_status = status + 0x5;
|
||||
if (fault) fault(addr, status + 0x5); /* Section translation fault */
|
||||
return 0xFFFFFFFF;
|
||||
case 1: /* Course page table (one entry per 4kB) */
|
||||
table = (uint32_t *)(intptr_t)phys_mem_ptr(entry & 0xFFFFFC00, 0x400);
|
||||
if (!table) {
|
||||
if (fault) error("Bad page table pointer");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
entry = table[addr >> 12 & 0xFF];
|
||||
break;
|
||||
case 2: /* Section (1MB) */
|
||||
page_size = 0x100000;
|
||||
ap = entry >> 6;
|
||||
goto section;
|
||||
case 3: /* Fine page table (one entry per 1kB) */
|
||||
table = (uint32_t *)(intptr_t)phys_mem_ptr(entry & 0xFFFFF000, 0x1000);
|
||||
if (!table) {
|
||||
if (fault) error("Bad page table pointer");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
entry = table[addr >> 10 & 0x3FF];
|
||||
break;
|
||||
}
|
||||
|
||||
status += 2;
|
||||
switch (entry & 3) {
|
||||
default: /* Invalid */
|
||||
if (s_status) *s_status = status + 0x5;
|
||||
if (fault) fault(addr, status + 0x5); /* Page translation fault */
|
||||
return 0xFFFFFFFF;
|
||||
case 1: /* Large page (64kB) */
|
||||
page_size = 0x10000;
|
||||
ap = entry >> (addr >> 13 & 6);
|
||||
break;
|
||||
case 2: /* Small page (4kB) */
|
||||
page_size = 0x1000;
|
||||
ap = entry >> (addr >> 9 & 6);
|
||||
break;
|
||||
case 3: /* Tiny page (1kB) */
|
||||
page_size = 0x400;
|
||||
ap = entry;
|
||||
break;
|
||||
}
|
||||
section:;
|
||||
|
||||
uint32_t domain_access = arm.domain_access_control >> (domain << 1) & 3;
|
||||
if (domain_access != 3) {
|
||||
if (!(domain_access & 1)) {
|
||||
/* 0 (No access) or 2 (Reserved)
|
||||
* Testing shows they both raise domain fault */
|
||||
if (s_status) *s_status = status + 0x9;
|
||||
if (fault) fault(addr, status + 0x9); /* Domain fault */
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
/* 1 (Client) - check access permission bits */
|
||||
switch (ap >> 4 & 3) {
|
||||
case 0: /* Controlled by S/R bits */
|
||||
switch (arm.control >> 8 & 3) {
|
||||
case 0: /* No access */
|
||||
case 3: /* Reserved - testing shows this behaves like 0 */
|
||||
perm_fault:
|
||||
if (s_status) *s_status = status + 0xD;
|
||||
if (fault) fault(addr, status + 0xD); /* Permission fault */
|
||||
return 0xFFFFFFFF;
|
||||
case 1: /* System - read-only for privileged, no access for user */
|
||||
if (USER_MODE() || writing)
|
||||
goto perm_fault;
|
||||
break;
|
||||
case 2: /* ROM - read-only */
|
||||
if (writing)
|
||||
goto perm_fault;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1: /* Read/write for privileged, no access for user */
|
||||
if (USER_MODE())
|
||||
goto perm_fault;
|
||||
break;
|
||||
case 2: /* Read/write for privileged, read-only for user */
|
||||
if (writing && USER_MODE())
|
||||
goto perm_fault;
|
||||
break;
|
||||
case 3: /* Read/write */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (entry & -page_size) | (addr & (page_size - 1));
|
||||
}
|
||||
|
||||
void mmu_check_priv(uint32_t addr, bool writing)
|
||||
{
|
||||
uint8_t status = 0;
|
||||
uint32_t saved_cpsr = arm.cpsr_low28;
|
||||
arm.cpsr_low28 &= ~3;
|
||||
mmu_translate(addr, writing, NULL, &status);
|
||||
arm.cpsr_low28 = saved_cpsr;
|
||||
if((status & 0xF) == 0xD)
|
||||
data_abort(addr, status);
|
||||
}
|
||||
|
||||
ac_entry *addr_cache = NULL;
|
||||
|
||||
// Keep a list of valid entries so we can invalidate everything quickly
|
||||
#define AC_VALID_MAX 256
|
||||
static uint32_t ac_valid_index;
|
||||
static uint32_t ac_valid_list[AC_VALID_MAX];
|
||||
|
||||
static void addr_cache_invalidate(int i) {
|
||||
AC_SET_ENTRY_INVALID(addr_cache[i], i >> 1 << 10)
|
||||
}
|
||||
|
||||
#if OS_HAS_PAGEFAULT_HANDLER
|
||||
|
||||
/* Since only a small fraction of the virtual address space, and therefore
|
||||
* only a small fraction of the pages making up addr_cache, will be in use
|
||||
* at a time, we can keep only a few pages committed and thereby reduce
|
||||
* the memory used by a lot. */
|
||||
#define AC_COMMIT_MAX 128
|
||||
#define AC_PAGE_SIZE 4096
|
||||
|
||||
bool addr_cache_pagefault(void *addr) {
|
||||
static uint8_t ac_commit_map[AC_NUM_ENTRIES * sizeof(ac_entry) / AC_PAGE_SIZE];
|
||||
static ac_entry *ac_commit_list[AC_COMMIT_MAX];
|
||||
static uint32_t ac_commit_index;
|
||||
|
||||
ac_entry *page = (ac_entry *)((uintptr_t)addr & -AC_PAGE_SIZE);
|
||||
uint32_t offset = page - addr_cache;
|
||||
if (offset >= AC_NUM_ENTRIES)
|
||||
return false;
|
||||
ac_entry *oldpage = ac_commit_list[ac_commit_index];
|
||||
if (oldpage) {
|
||||
//printf("Freeing %p, ", oldpage);
|
||||
os_sparse_decommit(oldpage, AC_PAGE_SIZE);
|
||||
ac_commit_map[offset / (AC_PAGE_SIZE / sizeof(ac_entry))] = 0;
|
||||
}
|
||||
//printf("Committing %p\n", page);
|
||||
if (!os_sparse_commit(page, AC_PAGE_SIZE))
|
||||
return false;
|
||||
ac_commit_map[offset / (AC_PAGE_SIZE / sizeof(ac_entry))] = 1;
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < (AC_PAGE_SIZE / sizeof(ac_entry)); i++)
|
||||
addr_cache_invalidate(offset + i);
|
||||
|
||||
ac_commit_list[ac_commit_index] = page;
|
||||
ac_commit_index = (ac_commit_index + 1) % AC_COMMIT_MAX;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void *addr_cache_miss(uint32_t virt, bool writing, fault_proc *fault) {
|
||||
ac_entry entry;
|
||||
uintptr_t phys = mmu_translate(virt, writing, fault, NULL);
|
||||
uint8_t *ptr = phys_mem_ptr(phys, 1);
|
||||
if (ptr && !(writing && (RAM_FLAGS((size_t)ptr & ~3) & RF_READ_ONLY))) {
|
||||
AC_SET_ENTRY_PTR(entry, virt, ptr)
|
||||
//printf("addr_cache_miss VA=%08X ptr=%p entry=%p\n", virt, ptr, entry);
|
||||
} else {
|
||||
AC_SET_ENTRY_PHYS(entry, virt, phys)
|
||||
//printf("addr_cache_miss VA=%08X PA=%08X entry=%p\n", virt, phys, entry);
|
||||
}
|
||||
uint32_t oldoffset = ac_valid_list[ac_valid_index];
|
||||
uint32_t offset = (virt >> 10) * 2 + writing;
|
||||
//if (ac_commit_map[oldoffset / (AC_PAGE_SIZE / sizeof(ac_entry))])
|
||||
addr_cache_invalidate(oldoffset);
|
||||
addr_cache[offset] = entry;
|
||||
ac_valid_list[ac_valid_index] = offset;
|
||||
ac_valid_index = (ac_valid_index + 1) % AC_VALID_MAX;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void addr_cache_flush(void) {
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
icacheInval(&pxa260CpuState.ic);//icache needs to be flushed when MMU state changes
|
||||
#endif
|
||||
|
||||
if (arm.control & 1) {
|
||||
void *table = phys_mem_ptr(arm.translation_table_base, 0x4000);
|
||||
if (!table)
|
||||
error("Bad translation table base register: %x", arm.translation_table_base);
|
||||
memcpy(mmu_translation_table, table, 0x4000);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < AC_VALID_MAX; i++) {
|
||||
uint32_t offset = ac_valid_list[i];
|
||||
// if (ac_commit_map[offset / (AC_PAGE_SIZE / sizeof(ac_entry))])
|
||||
addr_cache_invalidate(offset);
|
||||
}
|
||||
|
||||
flush_translations();
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#ifndef MAP_32BIT
|
||||
#define MAP_32BIT 0
|
||||
#endif
|
||||
|
||||
#include "armv5te/os/os.h"
|
||||
#include "armv5te/debug.h"
|
||||
#include "armv5te/mmu.h"
|
||||
|
||||
#ifdef IS_IOS_BUILD
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
int iOS_is_debugger_attached()
|
||||
{
|
||||
struct kinfo_proc info;
|
||||
size_t info_size = sizeof(info);
|
||||
int name[4];
|
||||
|
||||
name[0] = CTL_KERN;
|
||||
name[1] = KERN_PROC;
|
||||
name[2] = KERN_PROC_PID;
|
||||
name[3] = getpid();
|
||||
|
||||
info.kp_proc.p_flag = 0;
|
||||
|
||||
sysctl(name, 4, &info, &info_size, NULL, 0);
|
||||
|
||||
return (info.kp_proc.p_flag & P_TRACED) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *os_reserve(size_t size)
|
||||
{
|
||||
#ifdef __i386__
|
||||
// Has to have bit 31 zero
|
||||
void *ptr = mmap((void*)0x70000000, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON|MAP_32BIT, -1, 0);
|
||||
#else
|
||||
void *ptr = mmap((void*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
|
||||
#endif
|
||||
|
||||
if(ptr == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
msync(ptr, size, MS_SYNC|MS_INVALIDATE);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void os_free(void *ptr, size_t size)
|
||||
{
|
||||
if(ptr)
|
||||
munmap(ptr, size);
|
||||
}
|
||||
|
||||
void *os_alloc_executable(size_t size)
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// Has to be in 32-bit space for the JIT
|
||||
void *ptr = mmap((void*)0x30000000, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANON|MAP_32BIT, -1, 0);
|
||||
#else
|
||||
void *ptr = mmap((void*)0x0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANON, -1, 0);
|
||||
#endif
|
||||
|
||||
if(ptr == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
msync(ptr, size, MS_SYNC|MS_INVALIDATE);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
__attribute__((unused)) static void make_writable(void *addr)
|
||||
{
|
||||
uintptr_t ps = sysconf(_SC_PAGE_SIZE);
|
||||
void *prev = (void*)((uintptr_t)(addr) & (~(ps - 1)));
|
||||
if(mprotect(prev, ps, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
|
||||
emuprintf("mprotect failed.\n");
|
||||
}
|
||||
|
||||
void addr_cache_init()
|
||||
{
|
||||
// Only run this if not already initialized
|
||||
if(addr_cache)
|
||||
return;
|
||||
|
||||
addr_cache = mmap((void*)0, AC_NUM_ENTRIES * sizeof(ac_entry), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
|
||||
if(addr_cache == MAP_FAILED)
|
||||
{
|
||||
addr_cache = NULL;
|
||||
fprintf(stderr, "Failed to mmap addr_cache.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
#if !defined(AC_FLAGS)
|
||||
unsigned int i;
|
||||
for(unsigned int i = 0; i < AC_NUM_ENTRIES; ++i)
|
||||
{
|
||||
AC_SET_ENTRY_INVALID(addr_cache[i], (i >> 1) << 10)
|
||||
}
|
||||
#else
|
||||
memset(addr_cache, 0xFF, AC_NUM_ENTRIES * sizeof(ac_entry));
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) && !defined(NO_TRANSLATION)
|
||||
// Relocate the assembly code that wants addr_cache at a fixed address
|
||||
extern uint32_t *ac_reloc_start[] __asm__("ac_reloc_start"), *ac_reloc_end[] __asm__("ac_reloc_end");
|
||||
for(uint32_t **reloc = ac_reloc_start; reloc != ac_reloc_end; reloc++)
|
||||
{
|
||||
make_writable(*reloc);
|
||||
**reloc += (uintptr_t)addr_cache;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void addr_cache_deinit()
|
||||
{
|
||||
if(addr_cache)
|
||||
munmap(addr_cache, AC_NUM_ENTRIES * sizeof(ac_entry));
|
||||
|
||||
addr_cache = NULL;
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
#include "armv5te/os/os.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <assert.h>
|
||||
#include <conio.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <share.h>
|
||||
|
||||
#include "armv5te/emu.h"
|
||||
#include "armv5te/mmu.h"
|
||||
|
||||
void *os_reserve(size_t size)
|
||||
{
|
||||
return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void os_free(void *ptr, size_t size)
|
||||
{
|
||||
(void) size;
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#if OS_HAS_PAGEFAULT_HANDLER
|
||||
void *os_commit(void *addr, size_t size)
|
||||
{
|
||||
return VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void *os_sparse_commit(void *page, size_t size)
|
||||
{
|
||||
return VirtualAlloc(page, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void os_sparse_decommit(void *page, size_t size)
|
||||
{
|
||||
VirtualFree(page, size, MEM_DECOMMIT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *os_alloc_executable(size_t size)
|
||||
{
|
||||
return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
#if OS_HAS_PAGEFAULT_HANDLER
|
||||
static int addr_cache_exception(PEXCEPTION_RECORD er, void *x, void *y, void *z) {
|
||||
(void) x; (void) y; (void) z;
|
||||
if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
||||
if (addr_cache_pagefault((void *)er->ExceptionInformation[1]))
|
||||
return 0; // Continue execution
|
||||
}
|
||||
return 1; // Continue search
|
||||
}
|
||||
#endif
|
||||
|
||||
void addr_cache_init() {
|
||||
// Don't run more than once
|
||||
if(addr_cache)
|
||||
return;
|
||||
|
||||
DWORD flags = MEM_RESERVE;
|
||||
|
||||
#if defined(AC_FLAGS)
|
||||
// Commit memory to not trigger segfaults which make debugging a PITA
|
||||
flags |= MEM_COMMIT;
|
||||
#endif
|
||||
|
||||
addr_cache = VirtualAlloc(NULL, AC_NUM_ENTRIES * sizeof(ac_entry), flags, PAGE_READWRITE);
|
||||
if(!addr_cache){
|
||||
printf("Cant allocate addr_cache!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if !defined(AC_FLAGS)
|
||||
unsigned int i;
|
||||
for(unsigned int i = 0; i < AC_NUM_ENTRIES; ++i)
|
||||
{
|
||||
AC_SET_ENTRY_INVALID(addr_cache[i], (i >> 1) << 10)
|
||||
}
|
||||
#else
|
||||
memset(addr_cache, 0xFF, AC_NUM_ENTRIES * sizeof(ac_entry));
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) && !defined(NO_TRANSLATION)
|
||||
// Relocate the assembly code that wants addr_cache at a fixed address
|
||||
extern DWORD *ac_reloc_start[] __asm__("ac_reloc_start"), *ac_reloc_end[] __asm__("ac_reloc_end");
|
||||
DWORD **reloc;
|
||||
for (reloc = ac_reloc_start; reloc != ac_reloc_end; reloc++) {
|
||||
DWORD prot;
|
||||
VirtualProtect(*reloc, 4, PAGE_EXECUTE_READWRITE, &prot);
|
||||
**reloc += (DWORD)addr_cache;
|
||||
VirtualProtect(*reloc, 4, prot, &prot);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OS_HAS_PAGEFAULT_HANDLER
|
||||
void os_faulthandler_arm(os_exception_frame_t *frame)
|
||||
{
|
||||
assert(frame->prev == NULL);
|
||||
|
||||
frame->function = (void *)addr_cache_exception;
|
||||
asm ("movl %%fs:(%1), %0" : "=r" (frame->prev) : "r" (0));
|
||||
asm ("movl %0, %%fs:(%1)" : : "r" (frame), "r" (0));
|
||||
}
|
||||
|
||||
void os_faulthandler_unarm(os_exception_frame_t *frame)
|
||||
{
|
||||
assert(frame->prev != NULL);
|
||||
|
||||
asm ("movl %0, %%fs:(%1)" : : "r" (frame->prev), "r" (0));
|
||||
frame->prev = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void addr_cache_deinit() {
|
||||
if(!addr_cache)
|
||||
return;
|
||||
|
||||
#if defined(__i386__) && !defined(NO_TRANSLATION)
|
||||
// Undo the relocations
|
||||
extern DWORD *ac_reloc_start[] __asm__("ac_reloc_start"), *ac_reloc_end[] __asm__("ac_reloc_end");
|
||||
DWORD **reloc;
|
||||
for (reloc = ac_reloc_start; reloc != ac_reloc_end; reloc++)
|
||||
**reloc -= (DWORD)addr_cache;
|
||||
#endif
|
||||
|
||||
VirtualFree(addr_cache, 0, MEM_RELEASE);
|
||||
addr_cache = NULL;
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
#include "armv5te/asmcode.h"
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/debug.h"
|
||||
#include "armv5te/emu.h"
|
||||
#include "armv5te/mem.h"
|
||||
#include "armv5te/mmu.h"
|
||||
|
||||
static uint32_t shift(int type, uint32_t res, uint32_t count, int setcc) {
|
||||
//TODO: Verify!
|
||||
if (count == 0) {
|
||||
/* For all types, a count of 0 does nothing and does not affect carry. */
|
||||
return res;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
default: /* not used, obviously - here to shut up gcc warning */
|
||||
case 0: /* LSL */
|
||||
if (count >= 32) {
|
||||
if (setcc) arm.cpsr_c = (count == 32) ? (res & 1) : 0;
|
||||
return 0;
|
||||
}
|
||||
if (setcc) arm.cpsr_c = res >> (32 - count) & 1;
|
||||
return res << count;
|
||||
case 1: /* LSR */
|
||||
if (count >= 32) {
|
||||
if (setcc) arm.cpsr_c = (count == 32) ? (res >> 31) : 0;
|
||||
return 0;
|
||||
}
|
||||
if (setcc) arm.cpsr_c = res >> (count - 1) & 1;
|
||||
return res >> count;
|
||||
case 2: /* ASR */
|
||||
if (count >= 32) {
|
||||
count = 31;
|
||||
if (setcc) arm.cpsr_c = res >> 31;
|
||||
} else {
|
||||
if (setcc) arm.cpsr_c = res >> (count - 1) & 1;
|
||||
}
|
||||
return (int32_t)res >> count;
|
||||
case 3: /* ROR */
|
||||
count &= 31;
|
||||
res = res >> count | res << (32 - count);
|
||||
if (setcc) arm.cpsr_c = res >> 31;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_reg(int rn) {
|
||||
if (rn == 15) error("Invalid use of R15");
|
||||
return arm.reg[rn];
|
||||
}
|
||||
|
||||
static uint32_t get_reg_pc_thumb(int rn) {
|
||||
return arm.reg[rn] + ((rn == 15) ? 2 : 0);
|
||||
}
|
||||
|
||||
static inline void set_reg_pc0(int rn, uint32_t value) {
|
||||
arm.reg[rn] = value;
|
||||
}
|
||||
|
||||
/* Detect overflow after an addition or subtraction. */
|
||||
#define ADD_OVERFLOW(left, right, sum) ((int32_t)(((left) ^ (sum)) & ((right) ^ (sum))) < 0)
|
||||
#define SUB_OVERFLOW(left, right, sum) ((int32_t)(((left) ^ (right)) & ((left) ^ (sum))) < 0)
|
||||
|
||||
/* Do an addition, setting C/V flags accordingly. */
|
||||
static uint32_t add(uint32_t left, uint32_t right, int carry, int setcc) {
|
||||
uint32_t sum = left + right + carry;
|
||||
if (setcc) {
|
||||
if (sum < left) carry = 1;
|
||||
if (sum > left) carry = 0;
|
||||
arm.cpsr_c = carry;
|
||||
arm.cpsr_v = ADD_OVERFLOW(left, right, sum);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static inline void set_nz_flags(uint32_t value) {
|
||||
arm.cpsr_n = value >> 31;
|
||||
arm.cpsr_z = value == 0;
|
||||
}
|
||||
|
||||
void cpu_thumb_loop() {
|
||||
while (!exiting && cycle_count_delta < 0 && current_instr_size == 2) {
|
||||
uint16_t *insnp = (uint16_t*) read_instruction(arm.reg[15] & ~1);
|
||||
uint16_t insn = *insnp;
|
||||
uintptr_t flags = RAM_FLAGS((uintptr_t)insnp & ~3);
|
||||
|
||||
if (cpu_events != 0) {
|
||||
if (cpu_events & ~EVENT_DEBUG_STEP)
|
||||
break;
|
||||
goto enter_debugger;
|
||||
}
|
||||
|
||||
if (flags & (RF_EXEC_BREAKPOINT | RF_EXEC_DEBUG_NEXT)) {
|
||||
if (flags & RF_EXEC_BREAKPOINT)
|
||||
gui_debug_printf("Breakpoint at 0x%08X\n", arm.reg[15]);
|
||||
enter_debugger:
|
||||
uint32_t pc = arm.reg[15];
|
||||
debugger(DBG_EXEC_BREAKPOINT, 0);
|
||||
if(arm.reg[15] != pc)
|
||||
continue; // Debugger changed PC
|
||||
}
|
||||
|
||||
arm.reg[15] += 2;
|
||||
cycle_count_delta++;
|
||||
|
||||
#define CASE_x2(base) case base: case base+1
|
||||
#define CASE_x4(base) CASE_x2(base): CASE_x2(base+2)
|
||||
#define CASE_x8(base) CASE_x4(base): CASE_x4(base+4)
|
||||
#define REG0 arm.reg[insn & 7]
|
||||
#define REG3 arm.reg[insn >> 3 & 7]
|
||||
#define REG6 arm.reg[insn >> 6 & 7]
|
||||
#define REG8 arm.reg[insn >> 8 & 7]
|
||||
switch (insn >> 8) {
|
||||
CASE_x8(0x00): /* LSL Rd, Rm, #imm */
|
||||
CASE_x8(0x08): /* LSR Rd, Rm, #imm */
|
||||
CASE_x8(0x10): /* ASR Rd, Rm, #imm */
|
||||
set_nz_flags(REG0 = shift(insn >> 11, REG3, insn >> 6 & 31, true));
|
||||
break;
|
||||
CASE_x2(0x18): /* ADD Rd, Rn, Rm */ set_nz_flags(REG0 = add(REG3, REG6, 0, true)); break;
|
||||
CASE_x2(0x1A): /* SUB Rd, Rn, Rm */ set_nz_flags(REG0 = add(REG3, ~REG6, 1, true)); break;
|
||||
CASE_x2(0x1C): /* ADD Rd, Rn, #imm */ set_nz_flags(REG0 = add(REG3, insn >> 6 & 7, 0, true)); break;
|
||||
CASE_x2(0x1E): /* SUB Rd, Rn, #imm */ set_nz_flags(REG0 = add(REG3, ~(insn >> 6 & 7), 1, true)); break;
|
||||
CASE_x8(0x20): /* MOV Rd, #imm */ set_nz_flags(REG8 = insn & 0xFF); break;
|
||||
CASE_x8(0x28): /* CMP Rn, #imm */ set_nz_flags(add(REG8, ~(insn & 0xFF), 1, true)); break;
|
||||
CASE_x8(0x30): /* ADD Rd, #imm */ set_nz_flags(REG8 = add(REG8, insn & 0xFF, 0, true)); break;
|
||||
CASE_x8(0x38): /* SUB Rd, #imm */ set_nz_flags(REG8 = add(REG8, ~(insn & 0xFF), 1, true)); break;
|
||||
CASE_x4(0x40): {
|
||||
uint32_t *dst = ®0;
|
||||
uint32_t res;
|
||||
uint32_t src = REG3;
|
||||
switch (insn >> 6 & 15) {
|
||||
default:
|
||||
case 0x0: /* AND */ res = *dst &= src; break;
|
||||
case 0x1: /* EOR */ res = *dst ^= src; break;
|
||||
case 0x2: /* LSL */ res = *dst = shift(0, *dst, src & 0xFF, true); break;
|
||||
case 0x3: /* LSR */ res = *dst = shift(1, *dst, src & 0xFF, true); break;
|
||||
case 0x4: /* ASR */ res = *dst = shift(2, *dst, src & 0xFF, true); break;
|
||||
case 0x5: /* ADC */ res = *dst = add(*dst, src, arm.cpsr_c, true); break;
|
||||
case 0x6: /* SBC */ res = *dst = add(*dst, ~src, arm.cpsr_c, true); break;
|
||||
case 0x7: /* ROR */ res = *dst = shift(3, *dst, src & 0xFF, true); break;
|
||||
case 0x8: /* TST */ res = *dst & src; break;
|
||||
case 0x9: /* NEG */ res = *dst = add(0, ~src, 1, true); break;
|
||||
case 0xA: /* CMP */ res = add(*dst, ~src, 1, true); break;
|
||||
case 0xB: /* CMN */ res = add(*dst, src, 0, true); break;
|
||||
case 0xC: /* ORR */ res = *dst |= src; break;
|
||||
case 0xD: /* MUL */ res = *dst *= src; break;
|
||||
case 0xE: /* BIC */ res = *dst &= ~src; break;
|
||||
case 0xF: /* MVN */ res = *dst = ~src; break;
|
||||
}
|
||||
set_nz_flags(res);
|
||||
break;
|
||||
}
|
||||
case 0x44: { /* ADD Rd, Rm (high registers allowed) */
|
||||
uint32_t left = (insn >> 4 & 8) | (insn & 7), right = insn >> 3 & 15;
|
||||
set_reg_pc0(left, get_reg_pc_thumb(left) + get_reg_pc_thumb(right));
|
||||
break;
|
||||
}
|
||||
case 0x45: { /* CMP Rn, Rm (high registers allowed) */
|
||||
uint32_t left = (insn >> 4 & 8) | (insn & 7), right = insn >> 3 & 15;
|
||||
set_nz_flags(add(get_reg(left), ~get_reg_pc_thumb(right), 1, true));
|
||||
break;
|
||||
}
|
||||
case 0x46: { /* MOV Rd, Rm (high registers allowed) */
|
||||
uint32_t left = (insn >> 4 & 8) | (insn & 7), right = insn >> 3 & 15;
|
||||
set_reg_pc0(left, get_reg_pc_thumb(right));
|
||||
break;
|
||||
}
|
||||
case 0x47: { /* BX/BLX Rm (high register allowed) */
|
||||
uint32_t target = get_reg_pc_thumb(insn >> 3 & 15);
|
||||
if (insn & 0x80)
|
||||
arm.reg[14] = arm.reg[15] + 1;
|
||||
arm.reg[15] = target & ~1;
|
||||
if (!(target & 1)) {
|
||||
arm.cpsr_low28 &= ~0x20; /* Exit THUMB mode */
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
CASE_x8(0x48): /* LDR reg, [PC, #imm] */ REG8 = read_word(((arm.reg[15] + 2) & -4) + ((insn & 0xFF) << 2)); break;
|
||||
CASE_x2(0x50): /* STR Rd, [Rn, Rm] */ write_word(REG3 + REG6, REG0); break;
|
||||
CASE_x2(0x52): /* STRH Rd, [Rn, Rm] */ write_half(REG3 + REG6, REG0); break;
|
||||
CASE_x2(0x54): /* STRB Rd, [Rn, Rm] */ write_byte(REG3 + REG6, REG0); break;
|
||||
CASE_x2(0x56): /* LDRSB Rd, [Rn, Rm] */ REG0 = (int8_t)read_byte(REG3 + REG6); break;
|
||||
CASE_x2(0x58): /* LDR Rd, [Rn, Rm] */ REG0 = read_word(REG3 + REG6); break;
|
||||
CASE_x2(0x5A): /* LDRH Rd, [Rn, Rm] */ REG0 = read_half(REG3 + REG6); break;
|
||||
CASE_x2(0x5C): /* LDRB Rd, [Rn, Rm] */ REG0 = read_byte(REG3 + REG6); break;
|
||||
CASE_x2(0x5E): /* LDRSH Rd, [Rn, Rm] */ REG0 = (int16_t)read_half(REG3 + REG6); break;
|
||||
CASE_x8(0x60): /* STR Rd, [Rn, #imm] */ write_word(REG3 + (insn >> 4 & 124), REG0); break;
|
||||
CASE_x8(0x68): /* LDR Rd, [Rn, #imm] */ REG0 = read_word(REG3 + (insn >> 4 & 124)); break;
|
||||
CASE_x8(0x70): /* STRB Rd, [Rn, #imm] */ write_byte(REG3 + (insn >> 6 & 31), REG0); break;
|
||||
CASE_x8(0x78): /* LDRB Rd, [Rn, #imm] */ REG0 = read_byte(REG3 + (insn >> 6 & 31)); break;
|
||||
CASE_x8(0x80): /* STRH Rd, [Rn, #imm] */ write_half(REG3 + (insn >> 5 & 62), REG0); break;
|
||||
CASE_x8(0x88): /* LDRH Rd, [Rn, #imm] */ REG0 = read_half(REG3 + (insn >> 5 & 62)); break;
|
||||
CASE_x8(0x90): /* STR Rd, [SP, #imm] */ write_word(arm.reg[13] + ((insn & 0xFF) << 2), REG8); break;
|
||||
CASE_x8(0x98): /* LDR Rd, [SP, #imm] */ REG8 = read_word(arm.reg[13] + ((insn & 0xFF) << 2)); break;
|
||||
CASE_x8(0xA0): /* ADD Rd, PC, #imm */ REG8 = ((arm.reg[15] + 2) & -4) + ((insn & 0xFF) << 2); break;
|
||||
CASE_x8(0xA8): /* ADD Rd, SP, #imm */ REG8 = arm.reg[13] + ((insn & 0xFF) << 2); break;
|
||||
case 0xB0: /* ADD/SUB SP, #imm */
|
||||
arm.reg[13] += ((insn & 0x80) ? -(insn & 0x7F) : (insn & 0x7F)) << 2;
|
||||
break;
|
||||
|
||||
CASE_x2(0xB4): { /* PUSH {reglist[,LR]} */
|
||||
int i;
|
||||
uint32_t addr = arm.reg[13];
|
||||
for (i = 8; i >= 0; i--)
|
||||
addr -= (insn >> i & 1) * 4;
|
||||
uint32_t sp = addr;
|
||||
for (i = 0; i < 8; i++)
|
||||
if (insn >> i & 1)
|
||||
write_word(addr, arm.reg[i]), addr += 4;
|
||||
if (insn & 0x100)
|
||||
write_word(addr, arm.reg[14]);
|
||||
arm.reg[13] = sp;
|
||||
break;
|
||||
}
|
||||
|
||||
CASE_x2(0xBC): { /* POP {reglist[,PC]} */
|
||||
int i;
|
||||
uint32_t addr = arm.reg[13];
|
||||
for (i = 0; i < 8; i++)
|
||||
if (insn >> i & 1)
|
||||
arm.reg[i] = read_word(addr), addr += 4;
|
||||
if (insn & 0x100) {
|
||||
uint32_t target = read_word(addr); addr += 4;
|
||||
arm.reg[15] = target & ~1;
|
||||
if (!(target & 1)) {
|
||||
arm.cpsr_low28 &= ~0x20;
|
||||
arm.reg[13] = addr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
arm.reg[13] = addr;
|
||||
break;
|
||||
}
|
||||
case 0xBE:
|
||||
printf("Software breakpoint at %08X (%02X)\n", arm.reg[15], insn & 0xFF);
|
||||
debugger(DBG_EXEC_BREAKPOINT, 0);
|
||||
break;
|
||||
|
||||
CASE_x8(0xC0): { /* STMIA Rn!, {reglist} */
|
||||
int i;
|
||||
uint32_t addr = REG8;
|
||||
for (i = 0; i < 8; i++)
|
||||
if (insn >> i & 1)
|
||||
write_word(addr, arm.reg[i]), addr += 4;
|
||||
REG8 = addr;
|
||||
break;
|
||||
}
|
||||
CASE_x8(0xC8): { /* LDMIA Rn!, {reglist} */
|
||||
int i;
|
||||
uint32_t addr = REG8;
|
||||
uint32_t tmp = 0; // value not used, just suppressing uninitialized variable warning
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (insn >> i & 1) {
|
||||
if (i == (insn >> 8 & 7))
|
||||
tmp = read_word(addr);
|
||||
else
|
||||
arm.reg[i] = read_word(addr);
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
// must set address register last so it is unchanged on exception
|
||||
REG8 = addr;
|
||||
if (insn >> (insn >> 8 & 7) & 1)
|
||||
REG8 = tmp;
|
||||
break;
|
||||
}
|
||||
#define BRANCH_IF(cond) if (cond) arm.reg[15] += 2 + ((int8_t)insn << 1); break;
|
||||
case 0xD0: /* BEQ */ BRANCH_IF(arm.cpsr_z)
|
||||
case 0xD1: /* BNE */ BRANCH_IF(!arm.cpsr_z)
|
||||
case 0xD2: /* BCS */ BRANCH_IF(arm.cpsr_c)
|
||||
case 0xD3: /* BCC */ BRANCH_IF(!arm.cpsr_c)
|
||||
case 0xD4: /* BMI */ BRANCH_IF(arm.cpsr_n)
|
||||
case 0xD5: /* BPL */ BRANCH_IF(!arm.cpsr_n)
|
||||
case 0xD6: /* BVS */ BRANCH_IF(arm.cpsr_v)
|
||||
case 0xD7: /* BVC */ BRANCH_IF(!arm.cpsr_v)
|
||||
case 0xD8: /* BHI */ BRANCH_IF(arm.cpsr_c > arm.cpsr_z)
|
||||
case 0xD9: /* BLS */ BRANCH_IF(arm.cpsr_c <= arm.cpsr_z)
|
||||
case 0xDA: /* BGE */ BRANCH_IF(arm.cpsr_n == arm.cpsr_v)
|
||||
case 0xDB: /* BLT */ BRANCH_IF(arm.cpsr_n != arm.cpsr_v)
|
||||
case 0xDC: /* BGT */ BRANCH_IF(!arm.cpsr_z && arm.cpsr_n == arm.cpsr_v)
|
||||
case 0xDD: /* BLE */ BRANCH_IF(arm.cpsr_z || arm.cpsr_n != arm.cpsr_v)
|
||||
|
||||
case 0xDF: /* SWI */
|
||||
cpu_exception(EX_SWI);
|
||||
return; /* Exits THUMB mode */
|
||||
|
||||
CASE_x8(0xE0): /* B */ arm.reg[15] += 2 + ((int32_t)insn << 21 >> 20); break;
|
||||
CASE_x8(0xE8): { /* Second half of BLX */
|
||||
uint32_t target = (arm.reg[14] + ((insn & 0x7FF) << 1)) & ~3;
|
||||
arm.reg[14] = arm.reg[15] + 1;
|
||||
arm.reg[15] = target;
|
||||
arm.cpsr_low28 &= ~0x20; /* Exit THUMB mode */
|
||||
return;
|
||||
}
|
||||
CASE_x8(0xF0): /* First half of BL/BLX */
|
||||
arm.reg[14] = arm.reg[15] + 2 + ((int32_t)insn << 21 >> 9);
|
||||
break;
|
||||
CASE_x8(0xF8): { /* Second half of BL */
|
||||
uint32_t target = arm.reg[14] + ((insn & 0x7FF) << 1);
|
||||
arm.reg[14] = arm.reg[15] + 1;
|
||||
arm.reg[15] = target;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
undefined_instruction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,907 +0,0 @@
|
||||
/* How the AArch64 translation works:
|
||||
* AArch64 has enough registers to keep the entire ARM CPU state available.
|
||||
* In JIT'd code, these physical registers have a fixed role:
|
||||
* x0: First parameter and return value of helper functions in asmcode_aarch64.S
|
||||
* x1: Second parameter to helper functions in asmcode_aarch64.S
|
||||
* w2-w16: arm.reg[0] - arm.reg[14]
|
||||
* x17: Used as a scratch register for keeping a copy of the virtual cpsr_nzcv
|
||||
* (x18: Platform specific, can't use this)
|
||||
* x19: Pointer to the arm_state struct
|
||||
* x21-x24: Used as temporary registers by various subroutines
|
||||
* x25: Temporary register, not touched by (read|write)_asm routines
|
||||
* x26: Pointer to addr_cache contents
|
||||
* x27-x29: Not preserved, so don't touch.
|
||||
* x30: lr
|
||||
* x31: sp
|
||||
* x18 and x30 are callee-save, so must be saved and restored properly.
|
||||
* The other registers are part of the caller-save x0-x18 area and do not need
|
||||
* to be preserved. They need to be written back into the virtual arm struct
|
||||
* before calling into compiler-generated code though.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "armv5te/asmcode.h"
|
||||
#include "armv5te/cpudefs.h"
|
||||
#include "armv5te/emu.h"
|
||||
#include "armv5te/translate.h"
|
||||
#include "armv5te/mem.h"
|
||||
#include "armv5te/mmu.h"
|
||||
#include "armv5te/os/os.h"
|
||||
|
||||
#ifdef IS_IOS_BUILD
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifndef __aarch64__
|
||||
#error "I'm sorry Dave, I'm afraid I can't do that."
|
||||
#endif
|
||||
|
||||
/* Helper functions in asmcode_aarch64.S */
|
||||
extern "C" {
|
||||
extern void translation_next(uint32_t new_pc) __asm__("translation_next");
|
||||
extern void translation_next_bx(uint32_t new_pc) __asm__("translation_next_bx");
|
||||
extern void **translation_sp __asm__("translation_sp");
|
||||
#ifdef IS_IOS_BUILD
|
||||
int sys_cache_control(int function, void *start, size_t len);
|
||||
#endif
|
||||
}
|
||||
|
||||
enum Reg : uint8_t {
|
||||
R0 = 0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, SP, LR, PC
|
||||
};
|
||||
|
||||
enum PReg : uint8_t {
|
||||
W0 = 0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, W16, W17, W25 = 25, W26,
|
||||
X0 = W0, X1 = W1, X21 = 21, X30 = 30, X31 = 31, WZR = 31
|
||||
};
|
||||
|
||||
/* This function returns the physical register that contains the virtual register vreg.
|
||||
vreg must not be PC. */
|
||||
static PReg mapreg(const uint8_t vreg)
|
||||
{
|
||||
// See the first comment on register mapping
|
||||
assert(vreg < PC);
|
||||
return static_cast<PReg>(vreg + 2);
|
||||
}
|
||||
|
||||
uint32_t *translate_buffer = nullptr,
|
||||
*translate_current = nullptr;
|
||||
|
||||
#include "literalpool.h"
|
||||
|
||||
#define MAX_TRANSLATIONS 0x40000
|
||||
struct translation translation_table[MAX_TRANSLATIONS];
|
||||
uint32_t *jump_table[MAX_TRANSLATIONS*2],
|
||||
**jump_table_current = jump_table;
|
||||
static unsigned int next_translation_index = 0;
|
||||
|
||||
static void emit(const uint32_t instruction)
|
||||
{
|
||||
*translate_current++ = instruction;
|
||||
}
|
||||
|
||||
static __attribute__((unused)) void emit_brk()
|
||||
{
|
||||
emit(0xd4200000); // brk #0
|
||||
}
|
||||
|
||||
// Sets the physical register xd to imm
|
||||
static void emit_mov_imm(const PReg xd, uint64_t imm)
|
||||
{
|
||||
if(imm > 0xFFFF)
|
||||
{
|
||||
literalpool_add(imm);
|
||||
if(imm > 0xFFFFFFFFul)
|
||||
emit(0x58000000 | xd); // ldr xd, [pc, #<offset>]
|
||||
else
|
||||
emit(0x18000000 | xd); // ldr wd, [pc, #<offset>]
|
||||
return;
|
||||
}
|
||||
|
||||
emit(0xd2800000 | ((imm & 0xFFFF) << 5) | xd); // movz xd, #imm, lsl #0
|
||||
imm >>= 16;
|
||||
if(imm & 0xFFFF)
|
||||
emit(0xf2a00000 | ((imm & 0xFFFF) << 5) | xd); // movk xd, #imm, lsl #16
|
||||
|
||||
/* Literal pool used instead.
|
||||
|
||||
imm >>= 16;
|
||||
if(imm & 0xFFFF)
|
||||
emit(0xf2c00000 | ((imm & 0xFFFF) << 5) | xd); // movk xd, #imm, lsl #32
|
||||
|
||||
imm >>= 16;
|
||||
if(imm & 0xFFFF)
|
||||
emit(0xf2e00000 | ((imm & 0xFFFF) << 5) | xd); // movk xd, #imm, lsl #48
|
||||
*/
|
||||
}
|
||||
|
||||
static void emit_mov_reg(const PReg wd, const PReg wm)
|
||||
{
|
||||
emit(0x2a0003e0 | (wm << 16) | wd);
|
||||
}
|
||||
|
||||
void literalpool_fill()
|
||||
{
|
||||
for(unsigned int i = 0; i < literals_count; ++i)
|
||||
{
|
||||
auto &&literal = literals[i];
|
||||
if(!literal.inst)
|
||||
continue;
|
||||
|
||||
// Emit the literal
|
||||
uint32_t *literal_loc = translate_current;
|
||||
emit(static_cast<uint32_t>(literal.value));
|
||||
if(literal.value > 0xFFFFFFFFul)
|
||||
emit(static_cast<uint32_t>(literal.value >> 32));
|
||||
|
||||
// Fixup all literal references for the same value
|
||||
for(unsigned int j = i; j < literals_count; ++j)
|
||||
{
|
||||
auto &&literal_ref = literals[j];
|
||||
if(!literal_ref.inst || literal_ref.value != literal.value)
|
||||
continue;
|
||||
|
||||
ptrdiff_t diff = literal_loc - reinterpret_cast<uint32_t*>(literal_ref.inst);
|
||||
if(diff < -0x40000 || diff > 0x3ffff)
|
||||
error("Literal unreachable");
|
||||
|
||||
*reinterpret_cast<uint32_t*>(literal_ref.inst) |= diff << 5;
|
||||
literal_ref.inst = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
literals_count = 0;
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t maybe_branch(const void *target)
|
||||
{
|
||||
ptrdiff_t diff = reinterpret_cast<const uint32_t*>(target) - translate_current;
|
||||
if(diff > 0x3FFFFFF || -diff > 0x4000000)
|
||||
return 0;
|
||||
|
||||
return 0x12000000 | diff;
|
||||
}
|
||||
|
||||
// Jumps directly to target, destroys x21
|
||||
static void emit_jmp(const void *target)
|
||||
{
|
||||
/* uint32_t branch = maybe_branch(target);
|
||||
if(branch)
|
||||
return emit(branch);*/
|
||||
|
||||
emit_mov_imm(X21, reinterpret_cast<const uint64_t>(target));
|
||||
emit(0xd61f02a0); // br x21
|
||||
}
|
||||
|
||||
// Calls target, destroys x21 and x30
|
||||
static void emit_call(const void *target)
|
||||
{
|
||||
/* uint32_t branch = maybe_branch(target);
|
||||
if(branch)
|
||||
return emit(branch) | (1 << 31);*/
|
||||
|
||||
emit_mov_imm(X21, reinterpret_cast<const uint64_t>(target));
|
||||
emit(0xd63f02a0); // blr x21
|
||||
}
|
||||
|
||||
bool translate_init()
|
||||
{
|
||||
if(translate_buffer)
|
||||
return true;
|
||||
|
||||
#ifdef IS_IOS_BUILD
|
||||
#include <sys/syscall.h>
|
||||
if (!iOS_is_debugger_attached())
|
||||
{
|
||||
syscall(SYS_ptrace, 0 /*PTRACE_TRACEME*/, 0, 0, 0);
|
||||
if (!iOS_is_debugger_attached())
|
||||
{
|
||||
fprintf(stderr, "Was not able to force ptrace to allow JIT :(\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
translate_current = translate_buffer = reinterpret_cast<uint32_t*>(os_alloc_executable(INSN_BUFFER_SIZE));
|
||||
jump_table_current = jump_table;
|
||||
next_translation_index = 0;
|
||||
|
||||
return translate_buffer != nullptr;
|
||||
}
|
||||
|
||||
void translate_deinit()
|
||||
{
|
||||
if(!translate_buffer)
|
||||
return;
|
||||
|
||||
os_free(translate_buffer, INSN_BUFFER_SIZE);
|
||||
translate_current = translate_buffer = nullptr;
|
||||
}
|
||||
|
||||
void translate(uint32_t pc_start, uint32_t *insn_ptr_start)
|
||||
{
|
||||
if(next_translation_index >= MAX_TRANSLATIONS)
|
||||
{
|
||||
warn("Out of translation slots!");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef IS_IOS_BUILD
|
||||
// Mark translate_buffer as RW_
|
||||
mprotect(translate_buffer, INSN_BUFFER_SIZE, PROT_READ | PROT_WRITE);
|
||||
#endif
|
||||
|
||||
uint32_t **jump_table_start = jump_table_current;
|
||||
uint32_t pc = pc_start, *insn_ptr = insn_ptr_start;
|
||||
// Pointer to translation of current instruction
|
||||
uint32_t *translate_buffer_inst_start = translate_current;
|
||||
// Pointer to struct translation for this block
|
||||
translation *this_translation = &translation_table[next_translation_index];
|
||||
|
||||
// Whether we can avoid the jump to translation_next at the end
|
||||
bool jumps_away = false;
|
||||
// Whether to stop translating code
|
||||
bool stop_here = false;
|
||||
// cond_branch points to the b.cond, see below
|
||||
uint32_t *cond_branch = nullptr;
|
||||
|
||||
// We know this already. end_ptr will be set after the loop
|
||||
this_translation->jump_table = reinterpret_cast<void**>(jump_table_start);
|
||||
this_translation->start_ptr = insn_ptr_start;
|
||||
|
||||
while(1)
|
||||
{
|
||||
// Translate further?
|
||||
if(stop_here
|
||||
|| size_t((translate_current + 16) - translate_buffer) > (INSN_BUFFER_SIZE/sizeof(*translate_buffer))
|
||||
|| RAM_FLAGS(insn_ptr) & DONT_TRANSLATE
|
||||
|| (pc ^ pc_start) & ~0x3ff)
|
||||
goto exit_translation;
|
||||
|
||||
Instruction i;
|
||||
i.raw = *insn_ptr;
|
||||
|
||||
*jump_table_current = translate_current;
|
||||
|
||||
if(unlikely(i.cond == CC_NV))
|
||||
{
|
||||
if((i.raw & 0xFD70F000) == 0xF550F000)
|
||||
goto instruction_translated; // PLD
|
||||
else
|
||||
goto unimpl;
|
||||
}
|
||||
else if(unlikely(i.cond != CC_AL))
|
||||
{
|
||||
// Conditional instruction -> Generate jump over code with inverse condition
|
||||
cond_branch = translate_current;
|
||||
emit(0x54000000 | (i.cond ^ 1));
|
||||
}
|
||||
|
||||
if((i.raw & 0xE000090) == 0x0000090)
|
||||
{
|
||||
if(!i.mem_proc2.s && !i.mem_proc2.h)
|
||||
{
|
||||
// Not mem_proc2 -> multiply or swap
|
||||
if((i.raw & 0x0FB00000) == 0x01000000)
|
||||
goto unimpl; // SWP/SWPB not implemented
|
||||
|
||||
// MUL, UMLAL, etc.
|
||||
if(i.mult.rm == PC || i.mult.rs == PC
|
||||
|| i.mult.rn == PC || i.mult.rd == PC)
|
||||
goto unimpl; // PC as register not implemented
|
||||
|
||||
if(i.mult.s)
|
||||
goto unimpl; // setcc not implemented (not easily possible as no aarch64 instruction only changes n and z)
|
||||
|
||||
if ((i.raw & 0xFC000F0) == 0x0000090)
|
||||
{
|
||||
uint32_t instruction = 0x1B000000; // madd w0, w0, w0, w0
|
||||
|
||||
instruction |= (mapreg(i.mult.rs) << 16) | (mapreg(i.mult.rm) << 5) | mapreg(i.mult.rd);
|
||||
if(i.mult.a)
|
||||
instruction |= mapreg(i.mult.rn) << 10;
|
||||
else
|
||||
instruction |= WZR << 10;
|
||||
|
||||
emit(instruction);
|
||||
goto instruction_translated;
|
||||
}
|
||||
|
||||
goto unimpl; // UMULL, UMLAL, SMULL, SMLAL not implemented
|
||||
}
|
||||
|
||||
if(i.mem_proc2.s || !i.mem_proc2.h)
|
||||
goto unimpl; // Signed byte/halfword and doubleword not implemented
|
||||
|
||||
if(i.mem_proc2.rn == PC
|
||||
|| i.mem_proc2.rd == PC
|
||||
|| i.mem_proc2.rm == PC)
|
||||
goto unimpl; // PC as operand or dest. not implemented
|
||||
|
||||
// Load base into w0
|
||||
emit_mov_reg(W0, mapreg(i.mem_proc2.rn));
|
||||
|
||||
// Offset into w25
|
||||
if(i.mem_proc2.i) // Immediate offset
|
||||
emit_mov_imm(W25, (i.mem_proc2.immed_h << 4) | i.mem_proc2.immed_l);
|
||||
else // Register offset
|
||||
emit_mov_reg(W25, mapreg(i.mem_proc2.rm));
|
||||
|
||||
// Get final address..
|
||||
if(i.mem_proc2.p)
|
||||
{
|
||||
// ..into r0
|
||||
if(i.mem_proc2.u)
|
||||
emit(0x0b190000); // add w0, w0, w25
|
||||
else
|
||||
emit(0x4b190000); // sub w0, w0, w25
|
||||
|
||||
if(i.mem_proc2.w) // Writeback: final address into rn
|
||||
emit_mov_reg(mapreg(i.mem_proc2.rn), W0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ..into r5
|
||||
if(i.mem_proc2.u)
|
||||
emit(0x0b190019); // add w25, w0, w25
|
||||
else
|
||||
emit(0x4b190019); // sub w25, w0, w25
|
||||
}
|
||||
|
||||
if(i.mem_proc2.l)
|
||||
{
|
||||
emit_call(reinterpret_cast<void*>(read_half_asm));
|
||||
emit_mov_reg(mapreg(i.mem_proc2.rd), W0);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_mov_reg(W1, mapreg(i.mem_proc2.rd));
|
||||
emit_call(reinterpret_cast<void*>(write_half_asm));
|
||||
}
|
||||
|
||||
// Post-indexed: final address in r5 back into rn
|
||||
if(!i.mem_proc2.p)
|
||||
emit_mov_reg(mapreg(i.mem_proc2.rn), W25);
|
||||
|
||||
}
|
||||
else if((i.raw & 0xD900000) == 0x1000000)
|
||||
{
|
||||
if((i.raw & 0xFFFFFD0) == 0x12FFF10)
|
||||
{
|
||||
//B(L)X
|
||||
if(i.bx.rm == PC)
|
||||
goto unimpl;
|
||||
|
||||
emit_mov_reg(W0, mapreg(i.bx.rm));
|
||||
|
||||
if(i.bx.l)
|
||||
emit_mov_imm(mapreg(LR), pc + 4);
|
||||
else if(i.cond == CC_AL)
|
||||
stop_here = jumps_away = true;
|
||||
|
||||
emit_jmp(reinterpret_cast<void*>(translation_next_bx));
|
||||
}
|
||||
else
|
||||
goto unimpl;
|
||||
}
|
||||
else if((i.raw & 0xC000000) == 0x0000000)
|
||||
{
|
||||
// Data processing
|
||||
if(!i.data_proc.imm && i.data_proc.reg_shift) // reg shift
|
||||
goto unimpl;
|
||||
|
||||
if(i.data_proc.s
|
||||
&& !(i.data_proc.op == OP_ADD || i.data_proc.op == OP_SUB || i.data_proc.op == OP_CMP || i.data_proc.op == OP_CMN
|
||||
#ifndef SUPPORT_LINUX
|
||||
|| i.data_proc.op == OP_TST
|
||||
#endif
|
||||
))
|
||||
{
|
||||
/* We can't translate the S-bit that easily,
|
||||
as the barrel shifter output does not influence
|
||||
the carry flag anymore. */
|
||||
goto unimpl;
|
||||
}
|
||||
|
||||
if(i.data_proc.op == OP_RSB)
|
||||
{
|
||||
// RSB is not possible on AArch64, so try to convert it to SUB
|
||||
if(!i.data_proc.imm && !i.data_proc.reg_shift && i.data_proc.shift == SH_LSL && i.data_proc.shift_imm == 0)
|
||||
{
|
||||
// Swap rm and rn, change op to SUB
|
||||
unsigned int tmp = i.data_proc.rm;
|
||||
i.data_proc.rm = i.data_proc.rn;
|
||||
i.data_proc.rn = tmp;
|
||||
i.data_proc.op = OP_SUB;
|
||||
}
|
||||
else
|
||||
goto unimpl;
|
||||
}
|
||||
|
||||
if(i.data_proc.op == OP_RSC || i.data_proc.op == OP_TEQ)
|
||||
goto unimpl;
|
||||
|
||||
if(i.data_proc.shift == SH_ROR && !i.data_proc.imm && (i.data_proc.op == OP_SUB || i.data_proc.op == OP_ADD || i.data_proc.shift_imm == 0))
|
||||
goto unimpl; // ADD/SUB do not support ROR. RRX (encoded as ror #0) is not supported anywhere
|
||||
|
||||
// Using pc is not supported
|
||||
if(i.data_proc.rd == PC
|
||||
|| (!i.data_proc.imm && i.data_proc.rm == PC))
|
||||
goto unimpl;
|
||||
|
||||
// AArch64 ADC and SBC do not support a shifted reg
|
||||
if((i.data_proc.op == OP_ADC || i.data_proc.op == OP_SBC)
|
||||
&& (i.data_proc.shift != SH_LSL || i.data_proc.shift_imm != 0))
|
||||
goto unimpl;
|
||||
|
||||
// Shortcut for simple register mov (mov rd, rm)
|
||||
if((i.raw & 0xFFF0FF0) == 0x1a00000)
|
||||
{
|
||||
emit_mov_reg(mapreg(i.data_proc.rd), mapreg(i.data_proc.rm));
|
||||
goto instruction_translated;
|
||||
}
|
||||
|
||||
static const uint32_t opmap[] =
|
||||
{
|
||||
0x0A000000, // AND
|
||||
0x4A000000, // EOR
|
||||
0x4B000000, // SUB
|
||||
0, // RSB not possible
|
||||
0x0B000000, // ADD
|
||||
0x1A000000, // ADC (no shift!)
|
||||
0x5A000000, // SBC (no shift!)
|
||||
0, // RSC not possible
|
||||
#ifdef SUPPORT_LINUX
|
||||
0, // TST not possible, carry and overflow flags not identical
|
||||
#else
|
||||
0x6A00001F, // TST
|
||||
#endif
|
||||
0, // TEQ not possible
|
||||
0x6B00001F, // CMP
|
||||
0x2B00001F, // CMN
|
||||
0x2A000000, // ORR
|
||||
0x2A0003E0, // MOV (ORR with rn = wzr)
|
||||
0x0A200000, // BIC
|
||||
0x2A2003E0, // MVN (ORRN with rn = wzr)
|
||||
};
|
||||
|
||||
uint32_t instruction = opmap[i.data_proc.op];
|
||||
|
||||
if(i.data_proc.s)
|
||||
instruction |= 1 << 29;
|
||||
|
||||
if(i.data_proc.op < OP_TST || i.data_proc.op > OP_CMP)
|
||||
instruction |= mapreg(i.data_proc.rd);
|
||||
|
||||
if(i.data_proc.op != OP_MOV && i.data_proc.op != OP_MVN)
|
||||
{
|
||||
if(i.data_proc.rn != PC)
|
||||
instruction |= mapreg(i.data_proc.rn) << 5;
|
||||
else
|
||||
{
|
||||
emit_mov_imm(W1, pc + 8);
|
||||
instruction |= W1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
if(!i.data_proc.imm)
|
||||
{
|
||||
instruction |= mapreg(i.data_proc.rm) << 16;
|
||||
instruction |= i.data_proc.shift << 22;
|
||||
instruction |= i.data_proc.shift_imm << 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Could be optimized further,
|
||||
// some AArch64 ops support immediate values
|
||||
|
||||
uint32_t immed = i.data_proc.immed_8;
|
||||
uint8_t count = i.data_proc.rotate_imm << 1;
|
||||
if(count)
|
||||
immed = (immed >> count) | (immed << (32 - count));
|
||||
|
||||
if(i.data_proc.op == OP_MOV)
|
||||
{
|
||||
emit_mov_imm(mapreg(i.data_proc.rd), immed);
|
||||
goto instruction_translated;
|
||||
}
|
||||
|
||||
if(immed <= 0xFFF
|
||||
&& (i.data_proc.op == OP_ADD || i.data_proc.op == OP_SUB
|
||||
|| i.data_proc.op == OP_CMP || i.data_proc.op == OP_CMN))
|
||||
{
|
||||
/* Those instructions support a normal 12bit (optionally shifted left by 12) immediate.
|
||||
This is not the case for logical instructions, they use awfully complicated useless
|
||||
terrible garbage called "bitmask operand" that not even binutils can encode properly. */
|
||||
instruction &= ~(0x1E000000);
|
||||
instruction |= 1 << 28 | (immed << 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_mov_imm(W0, immed);
|
||||
/* All those operations are nops (or with 0)
|
||||
instruction |= W0 << 16;
|
||||
instruction |= SH_LSL << 22;
|
||||
instruction |= 0 << 10;*/
|
||||
}
|
||||
}
|
||||
|
||||
emit(instruction);
|
||||
}
|
||||
else if((i.raw & 0xFF000F0) == 0x7F000F0)
|
||||
goto unimpl; // undefined
|
||||
else if((i.raw & 0xC000000) == 0x4000000)
|
||||
{
|
||||
// Memory access: LDR, STRB, etc.
|
||||
// User mode access not implemented
|
||||
if(!i.mem_proc.p && i.mem_proc.w)
|
||||
goto unimpl;
|
||||
|
||||
if(i.mem_proc.not_imm && (i.mem_proc.rm == PC || (i.mem_proc.shift == SH_ROR && i.mem_proc.shift_imm == 0)))
|
||||
goto unimpl;
|
||||
|
||||
if((i.mem_proc.rd == i.mem_proc.rn || i.mem_proc.rn == PC) && (!i.mem_proc.p || i.mem_proc.w))
|
||||
goto unimpl; // Writeback into PC not implemented
|
||||
|
||||
bool offset_is_zero = !i.mem_proc.not_imm && i.mem_proc.immed == 0;
|
||||
|
||||
// Address into w0
|
||||
if(i.mem_proc.rn != PC)
|
||||
emit_mov_reg(W0, mapreg(i.mem_proc.rn));
|
||||
else if(i.mem_proc.not_imm)
|
||||
emit_mov_imm(W0, pc + 8);
|
||||
else // Address known
|
||||
{
|
||||
int offset = i.mem_proc.u ? i.mem_proc.immed :
|
||||
-i.mem_proc.immed;
|
||||
|
||||
emit_mov_imm(W0, pc + 8 + offset);
|
||||
offset_is_zero = true;
|
||||
}
|
||||
|
||||
// Skip offset calculation
|
||||
if(offset_is_zero)
|
||||
goto no_offset;
|
||||
|
||||
// Offset into w25
|
||||
if(!i.mem_proc.not_imm) // Immediate offset
|
||||
emit_mov_imm(W25, i.mem_proc.immed);
|
||||
else // Register offset, shifted
|
||||
{
|
||||
uint32_t instruction = 0x2a0003f9; // orr w25, wzr, wX, <shift>, #<amount>
|
||||
instruction |= mapreg(i.mem_proc.rm) << 16;
|
||||
instruction |= i.mem_proc.shift << 22;
|
||||
instruction |= i.mem_proc.shift_imm << 10;
|
||||
|
||||
emit(instruction);
|
||||
}
|
||||
|
||||
// Get final address..
|
||||
if(i.mem_proc.p)
|
||||
{
|
||||
// ..into r0
|
||||
if(i.mem_proc.u)
|
||||
emit(0x0b190000); // add w0, w0, w25
|
||||
else
|
||||
emit(0x4b190000); // sub w0, w0, w25
|
||||
|
||||
// It has to be stored AFTER the memory access, to be able
|
||||
// to perform the access again after an abort.
|
||||
if(i.mem_proc.w) // Writeback: final address into w25
|
||||
emit_mov_reg(W25, W0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ..into w25
|
||||
if(i.mem_proc.u)
|
||||
emit(0x0b190019); // add w25, w0, w25
|
||||
else
|
||||
emit(0x4b190019); // sub w25, w0, w25
|
||||
}
|
||||
|
||||
no_offset:
|
||||
if(i.mem_proc.l)
|
||||
{
|
||||
emit_call(reinterpret_cast<void*>(i.mem_proc.b ? read_byte_asm : read_word_asm));
|
||||
if(i.mem_proc.rd != PC)
|
||||
emit_mov_reg(mapreg(i.mem_proc.rd), W0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(i.mem_proc.rd != PC)
|
||||
emit_mov_reg(W1, mapreg(i.mem_proc.rd)); // w1 is the value
|
||||
else
|
||||
emit_mov_imm(W1, pc + 12);
|
||||
|
||||
emit_call(reinterpret_cast<void*>(i.mem_proc.b ? write_byte_asm : write_word_asm));
|
||||
}
|
||||
|
||||
if(!offset_is_zero && (!i.mem_proc.p || i.mem_proc.w))
|
||||
emit_mov_reg(mapreg(i.mem_proc.rn), W25);
|
||||
|
||||
// Jump after writeback, to support post-indexed jumps
|
||||
if(i.mem_proc.l && i.mem_proc.rd == PC)
|
||||
{
|
||||
// pc is destination register
|
||||
emit_jmp(reinterpret_cast<void*>(translation_next_bx));
|
||||
// It's an unconditional jump
|
||||
if(i.cond == CC_AL)
|
||||
jumps_away = stop_here = true;
|
||||
}
|
||||
}
|
||||
else if((i.raw & 0xE000000) == 0x8000000)
|
||||
{
|
||||
// LDM/STM
|
||||
if(i.mem_multi.s)
|
||||
goto unimpl; // Exception return or usermode not implemented
|
||||
|
||||
if(i.mem_multi.rn == PC)
|
||||
goto unimpl;
|
||||
|
||||
uint16_t reglist = i.mem_multi.reglist;
|
||||
if(reglist & (1 << i.mem_multi.rn))
|
||||
goto unimpl; // Loading/Saving address register
|
||||
|
||||
int count = __builtin_popcount(reglist), offset, wb_offset;
|
||||
|
||||
if(i.mem_multi.u) // Increment
|
||||
{
|
||||
wb_offset = count * 4;
|
||||
offset = 0;
|
||||
}
|
||||
else // Decrement
|
||||
{
|
||||
wb_offset = count * -4;
|
||||
offset = wb_offset;
|
||||
}
|
||||
|
||||
if(i.mem_multi.p == i.mem_multi.u)
|
||||
offset += 4;
|
||||
|
||||
// Base reg in w25
|
||||
emit_mov_reg(W25, mapreg(i.mem_multi.rn));
|
||||
unsigned int reg = 0;
|
||||
while(reglist)
|
||||
{
|
||||
if((reglist & 1) == 0)
|
||||
goto next;
|
||||
|
||||
if(offset >= 0)
|
||||
emit(0x11000320 | (offset << 10)); // add w0, w25, #offset
|
||||
else
|
||||
emit(0x51000320 | (-offset << 10)); // sub w0, w25, #-offset
|
||||
|
||||
if(i.mem_multi.l)
|
||||
{
|
||||
emit_call(reinterpret_cast<void*>(read_word_asm));
|
||||
if(reg != PC)
|
||||
emit_mov_reg(mapreg(reg), W0);
|
||||
//else written below
|
||||
}
|
||||
else
|
||||
{
|
||||
if(reg == PC)
|
||||
emit_mov_imm(W1, pc + 12);
|
||||
else
|
||||
emit_mov_reg(W1, mapreg(reg));
|
||||
|
||||
emit_call(reinterpret_cast<void*>(write_word_asm));
|
||||
}
|
||||
|
||||
offset += 4;
|
||||
next:
|
||||
reglist >>= 1;
|
||||
++reg;
|
||||
}
|
||||
|
||||
if(i.mem_multi.w)
|
||||
{
|
||||
if(wb_offset >= 0)
|
||||
emit(0x11000320 | (wb_offset << 10) | mapreg(i.mem_multi.rn)); // add wN, w25, #wb_offset
|
||||
else
|
||||
emit(0x51000320 | (-wb_offset << 10) | mapreg(i.mem_multi.rn)); // sub wN, w25, #-wb_offset
|
||||
}
|
||||
|
||||
if(i.mem_multi.l && (i.mem_multi.reglist & (1 << PC))) // Loading PC
|
||||
{
|
||||
// PC already in W0 (last one loaded)
|
||||
emit_jmp(reinterpret_cast<void*>(translation_next_bx));
|
||||
if(i.cond == CC_AL)
|
||||
jumps_away = stop_here = true;
|
||||
}
|
||||
}
|
||||
else if((i.raw & 0xE000000) == 0xA000000)
|
||||
{
|
||||
if(i.branch.l)
|
||||
{
|
||||
// Save return address in LR
|
||||
emit_mov_imm(mapreg(LR), pc + 4);
|
||||
}
|
||||
else if(i.cond == CC_AL)
|
||||
jumps_away = stop_here = true;
|
||||
|
||||
uint32_t addr = pc + ((int32_t)(i.raw << 8) >> 6) + 8;
|
||||
uint32_t *ptr = reinterpret_cast<uint32_t*>(try_ptr(addr));
|
||||
|
||||
if(ptr == nullptr)
|
||||
{
|
||||
emit_mov_imm(W0, addr);
|
||||
emit_jmp(reinterpret_cast<void*>(translation_next));
|
||||
}
|
||||
else if(!(RAM_FLAGS(ptr) & RF_CODE_TRANSLATED))
|
||||
{
|
||||
// Update PC manually
|
||||
emit_mov_imm(W0, addr);
|
||||
emit(0xb9003e60); // str w0, [x19, #15*4]
|
||||
emit_mov_imm(X0, uintptr_t(ptr));
|
||||
emit_jmp(reinterpret_cast<void*>(translation_jmp_ptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get address of translated code to jump to it
|
||||
translation *target_translation = &translation_table[RAM_FLAGS(ptr) >> RFS_TRANSLATION_INDEX];
|
||||
uintptr_t jmp_target = reinterpret_cast<uintptr_t>(target_translation->jump_table[ptr - target_translation->start_ptr]);
|
||||
|
||||
// Update PC manually
|
||||
emit_mov_imm(W0, addr);
|
||||
emit(0xb9003e60); // str w0, [x19, #15*4]
|
||||
emit_mov_imm(X0, jmp_target);
|
||||
emit_jmp(reinterpret_cast<void*>(translation_jmp));
|
||||
}
|
||||
}
|
||||
else
|
||||
goto unimpl;
|
||||
|
||||
instruction_translated:
|
||||
|
||||
if(cond_branch)
|
||||
{
|
||||
// Fixup the branch above
|
||||
*cond_branch |= ((translate_current - cond_branch) & 0x7FFFF) << 5;
|
||||
cond_branch = nullptr;
|
||||
}
|
||||
|
||||
RAM_FLAGS(insn_ptr) |= (RF_CODE_TRANSLATED | next_translation_index << RFS_TRANSLATION_INDEX);
|
||||
|
||||
++jump_table_current;
|
||||
++insn_ptr;
|
||||
pc += 4;
|
||||
}
|
||||
|
||||
unimpl:
|
||||
// Throw away partial translation
|
||||
translate_current = *jump_table_current;
|
||||
RAM_FLAGS(insn_ptr) |= RF_CODE_NO_TRANSLATE;
|
||||
|
||||
exit_translation:
|
||||
|
||||
if(insn_ptr == insn_ptr_start)
|
||||
{
|
||||
#ifdef IS_IOS_BUILD
|
||||
// Mark translate_buffer as R_X
|
||||
// Even if no translation was done, pages got marked RW_
|
||||
mprotect(translate_buffer, INSN_BUFFER_SIZE, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
|
||||
// No virtual instruction got translated, just drop everything
|
||||
translate_current = translate_buffer_inst_start;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!jumps_away)
|
||||
{
|
||||
uint32_t *ptr = reinterpret_cast<uint32_t*>(try_ptr(pc));
|
||||
|
||||
if(ptr == nullptr)
|
||||
{
|
||||
emit_mov_imm(W0, pc);
|
||||
emit_jmp(reinterpret_cast<void*>(translation_next));
|
||||
}
|
||||
else if(!(RAM_FLAGS(ptr) & RF_CODE_TRANSLATED))
|
||||
{
|
||||
// Update PC manually
|
||||
emit_mov_imm(W0, pc);
|
||||
emit(0xb9003e60); // str w0, [x19, #15*4]
|
||||
emit_mov_imm(X0, uintptr_t(ptr));
|
||||
emit_jmp(reinterpret_cast<void*>(translation_jmp_ptr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get address of translated code to jump to it
|
||||
translation *target_translation = &translation_table[RAM_FLAGS(ptr) >> RFS_TRANSLATION_INDEX];
|
||||
uintptr_t jmp_target = reinterpret_cast<uintptr_t>(target_translation->jump_table[ptr - target_translation->start_ptr]);
|
||||
|
||||
// Update PC manually
|
||||
emit_mov_imm(W0, pc);
|
||||
emit(0xb9003e60); // str w0, [x19, #15*4]
|
||||
emit_mov_imm(X0, jmp_target);
|
||||
emit_jmp(reinterpret_cast<void*>(translation_jmp));
|
||||
}
|
||||
}
|
||||
|
||||
// Only flush cache until the literal pool
|
||||
uint32_t *code_end = translate_current;
|
||||
// Emit the literal pool
|
||||
literalpool_fill();
|
||||
|
||||
this_translation->end_ptr = insn_ptr;
|
||||
this_translation->unused = reinterpret_cast<uintptr_t>(translate_current);
|
||||
|
||||
next_translation_index += 1;
|
||||
|
||||
// Flush the instruction cache
|
||||
#ifdef IS_IOS_BUILD
|
||||
// Mark translate_buffer as R_X
|
||||
mprotect(translate_buffer, INSN_BUFFER_SIZE, PROT_READ | PROT_EXEC);
|
||||
sys_cache_control(1 /* kCacheFunctionPrepareForExecution */, jump_table_start[0], (code_end-jump_table_start[0])*4);
|
||||
#else
|
||||
__builtin___clear_cache((char*)jump_table_start[0], (char*)code_end);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _invalidate_translation(int index)
|
||||
{
|
||||
/* Disabled for now. write_action not called in asmcode_aarch64.S so this can't happen
|
||||
and translation_pc_ptr is inaccurate due to translation_jmp anyway.
|
||||
|
||||
uint32_t flags = RAM_FLAGS(translation_pc_ptr);
|
||||
if ((flags & RF_CODE_TRANSLATED) && (int)(flags >> RFS_TRANSLATION_INDEX) == index)
|
||||
error("Cannot modify currently executing code block.");
|
||||
*/
|
||||
|
||||
uint32_t *start = translation_table[index].start_ptr;
|
||||
uint32_t *end = translation_table[index].end_ptr;
|
||||
for (; start < end; start++)
|
||||
RAM_FLAGS(start) &= ~(RF_CODE_TRANSLATED | (~0u << RFS_TRANSLATION_INDEX));
|
||||
}
|
||||
|
||||
void flush_translations()
|
||||
{
|
||||
for(unsigned int index = 0; index < next_translation_index; index++)
|
||||
_invalidate_translation(index);
|
||||
|
||||
next_translation_index = 0;
|
||||
translate_current = translate_buffer;
|
||||
jump_table_current = jump_table;
|
||||
}
|
||||
|
||||
void invalidate_translation(int index)
|
||||
{
|
||||
/* Due to translation_jmp using absolute pointers in the JIT, we can't just
|
||||
invalidate a single translation. */
|
||||
#ifdef SUPPORT_LINUX
|
||||
(void) index;
|
||||
flush_translations();
|
||||
#else
|
||||
_invalidate_translation(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
void translate_fix_pc()
|
||||
{
|
||||
if (!translation_sp)
|
||||
return;
|
||||
|
||||
uint32_t *insnp = reinterpret_cast<uint32_t*>(try_ptr(arm.reg[15]));
|
||||
uint32_t flags = 0;
|
||||
if(!insnp || !((flags = RAM_FLAGS(insnp)) & RF_CODE_TRANSLATED))
|
||||
return error("Couldn't get PC for fault");
|
||||
|
||||
int index = flags >> RFS_TRANSLATION_INDEX;
|
||||
assert(insnp >= translation_table[index].start_ptr);
|
||||
assert(insnp < translation_table[index].end_ptr);
|
||||
|
||||
void *ret_pc = translation_sp[-2];
|
||||
|
||||
unsigned int jump_index = insnp - translation_table[index].start_ptr;
|
||||
unsigned int translation_insts = translation_table[index].end_ptr - translation_table[index].start_ptr;
|
||||
|
||||
for(unsigned int i = jump_index; ret_pc > translation_table[index].jump_table[i] && i < translation_insts; ++i)
|
||||
arm.reg[15] += 4;
|
||||
|
||||
cycle_count_delta -= translation_table[index].end_ptr - insnp;
|
||||
translation_sp = nullptr;
|
||||
|
||||
assert(!(arm.cpsr_low28 & 0x20));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,167 +0,0 @@
|
||||
#include "armv5te/uArm/uArmGlue.h"
|
||||
#include "armv5te/uArm/CPU_2.h"
|
||||
|
||||
#include "emulator.h"
|
||||
#include "armv5te/cpu.h"
|
||||
#include "armv5te/asmcode.h"
|
||||
#include "armv5te/cpudefs.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pxa260/pxa260.h"
|
||||
}
|
||||
|
||||
|
||||
static ArmCoprocessor uArmCp14;
|
||||
static ArmCoprocessor uArmCp15;
|
||||
|
||||
|
||||
Boolean uArmCp14RegXferF (struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
//if(!cpu->coproc[vb8].regXfer(cpu, cpu->coproc[vb8].userData, specialInstr, (instr & 0x00100000UL) != 0, (instr >> 21) & 0x07, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07)) goto invalid_instr;
|
||||
Instruction inst;
|
||||
|
||||
inst.raw = 0xE000E10 | op1 << 21 | Rx << 12 | CRn << 16 | CRm | op2 << 5;
|
||||
|
||||
if(MRC)
|
||||
inst.raw |= 0x00100000;
|
||||
|
||||
do_cp14_instruction(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean uArmCp14DatProcF (struct ArmCpu* cpu, void* userData, Boolean two/* CDP2 ? */, UInt8 op1, UInt8 CRd, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
debugLog("uARM CP14 dat proc unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp14MemAccsF (struct ArmCpu* cpu, void* userData, Boolean two /* LDC2/STC2 ? */, Boolean N, Boolean store, UInt8 CRd, UInt32 addr, UInt8* option /* NULL if none */){
|
||||
debugLog("uARM CP14 mem access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp14TwoRegF (struct ArmCpu* cpu, void* userData, Boolean MRRC, UInt8 op, UInt8 Rd, UInt8 Rn, UInt8 CRm){
|
||||
debugLog("uARM CP14 2 reg access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp15RegXferF (struct ArmCpu* cpu, void* userData, Boolean two/* MCR2/MRC2 ? */, Boolean MRC, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
//if(!cpu->coproc[vb8].regXfer(cpu, cpu->coproc[vb8].userData, specialInstr, (instr & 0x00100000UL) != 0, (instr >> 21) & 0x07, (instr >> 12) & 0x0F, (instr >> 16) & 0x0F, instr & 0x0F, (instr >> 5) & 0x07)) goto invalid_instr;
|
||||
Instruction inst;
|
||||
|
||||
if(two)
|
||||
debugLog("uARM unimplemented 2 register CP15 access\n");
|
||||
|
||||
if(Rx == 15)
|
||||
set_cpsr_full(pxa260CpuState.CPSR);
|
||||
else
|
||||
arm.reg[Rx] = pxa260CpuState.regs[Rx];
|
||||
|
||||
inst.raw = 0xE000F10 | op1 << 21 | Rx << 12 | CRn << 16 | CRm | op2 << 5;
|
||||
|
||||
if(MRC)
|
||||
inst.raw |= 0x00100000;
|
||||
|
||||
do_cp15_instruction(inst);
|
||||
//addr_cache_flush handles icache flushing too
|
||||
|
||||
if(Rx == 15)
|
||||
pxa260CpuState.CPSR = get_cpsr();//this could be catastrophic in any other circumstance but only the CPSR data flags can be changed by CP15
|
||||
else
|
||||
pxa260CpuState.regs[Rx] = arm.reg[Rx];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean uArmCp15DatProcF (struct ArmCpu* cpu, void* userData, Boolean two/* CDP2 ? */, UInt8 op1, UInt8 CRd, UInt8 CRn, UInt8 CRm, UInt8 op2){
|
||||
debugLog("uARM CP15 dat proc unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp15MemAccsF (struct ArmCpu* cpu, void* userData, Boolean two /* LDC2/STC2 ? */, Boolean N, Boolean store, UInt8 CRd, UInt32 addr, UInt8* option /* NULL if none */){
|
||||
debugLog("uARM CP15 mem access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmCp15TwoRegF (struct ArmCpu* cpu, void* userData, Boolean MRRC, UInt8 op, UInt8 Rd, UInt8 Rn, UInt8 CRm){
|
||||
debugLog("uARM CP15 2 reg access unimplemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean uArmMemAccess(struct ArmCpu* cpu, void* buf, UInt32 vaddr, UInt8 size, Boolean write, Boolean priviledged, UInt8* fsr){
|
||||
if(write){
|
||||
switch(size){
|
||||
case 1:
|
||||
write_byte(vaddr, *(uint8_t*)buf);
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
write_half(vaddr, *(uint16_t*)buf);
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
write_word(vaddr, *(uint32_t*)buf);
|
||||
return true;
|
||||
|
||||
default:
|
||||
debugLog("uARM wrote memory with invalid byte count:%d\n", size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
switch(size){
|
||||
case 1:
|
||||
*(uint8_t*)buf = read_byte(vaddr);
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
*(uint16_t*)buf = read_half(vaddr);
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
*(uint32_t*)buf = read_word(vaddr);
|
||||
return true;
|
||||
|
||||
case 32:
|
||||
((uint32_t*)buf)[0] = read_word(vaddr);
|
||||
((uint32_t*)buf)[1] = read_word(vaddr + 4);
|
||||
((uint32_t*)buf)[2] = read_word(vaddr + 8);
|
||||
((uint32_t*)buf)[3] = read_word(vaddr + 12);
|
||||
((uint32_t*)buf)[4] = read_word(vaddr + 16);
|
||||
((uint32_t*)buf)[5] = read_word(vaddr + 20);
|
||||
((uint32_t*)buf)[6] = read_word(vaddr + 24);
|
||||
((uint32_t*)buf)[7] = read_word(vaddr + 28);
|
||||
return true;
|
||||
|
||||
default:
|
||||
debugLog("uARM read memory with invalid byte count:%d\n", size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boolean uArmHypercall(struct ArmCpu* cpu){
|
||||
//no hypercalls
|
||||
return true;
|
||||
}
|
||||
|
||||
void uArmEmulErr (struct ArmCpu* cpu, const char* err_str){
|
||||
debugLog("uARM error:%s\n", err_str);
|
||||
}
|
||||
|
||||
void uArmSetFaultAddr(struct ArmCpu* cpu, UInt32 adr, UInt8 faultStatus){
|
||||
debugLog("uARM set fault addr:0x%08X, status:0x%02X\n", adr, faultStatus);
|
||||
}
|
||||
|
||||
void uArmInitCpXX(ArmCpu* cpu){
|
||||
uArmCp14.regXfer = uArmCp14RegXferF;
|
||||
uArmCp14.dataProcessing = uArmCp14DatProcF;
|
||||
uArmCp14.memAccess = uArmCp14MemAccsF;
|
||||
uArmCp14.twoRegF = uArmCp14TwoRegF;
|
||||
|
||||
uArmCp15.regXfer = uArmCp15RegXferF;
|
||||
uArmCp15.dataProcessing = uArmCp15DatProcF;
|
||||
uArmCp15.memAccess = uArmCp15MemAccsF;
|
||||
uArmCp15.twoRegF = uArmCp15TwoRegF;
|
||||
|
||||
cpuCoprocessorRegister(cpu, 14, &uArmCp14);
|
||||
cpuCoprocessorRegister(cpu, 15, &uArmCp15);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
# m68k Module
|
||||
add_library(MuCoreAudio STATIC
|
||||
blip_buf.c)
|
||||
|
||||
# Make this position independent so it can be linked into shared libraries
|
||||
set_property(TARGET MuCoreAudio
|
||||
PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Includes for the project
|
||||
target_include_directories(MuCoreAudio PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/include")
|
||||
@@ -1,6 +1,6 @@
|
||||
/* blip_buf 1.1.0. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "audio/blip_buf.h"
|
||||
#include "blip_buf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
40
src/dbvz.c
40
src/dbvz.c
@@ -475,26 +475,17 @@ uint8_t dbvzGetRegister8(uint32_t address){
|
||||
//PDSEL lacks the bottom 4 bits but that is handled on write
|
||||
return registerArrayRead8(address);
|
||||
|
||||
case URX1:
|
||||
case URX1 + 1:
|
||||
case URX2:
|
||||
case URX2 + 1:
|
||||
return registerArrayRead16(address);
|
||||
|
||||
default:
|
||||
printHwRegAccess(address, 0, 8, false);
|
||||
|
||||
//bootloader
|
||||
if(address >= 0xE00)
|
||||
return registerArrayRead8(address);
|
||||
|
||||
printHwRegAccess(address, 0, 8, false);
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t dbvzGetRegister16(uint32_t address){
|
||||
uint16_t bit;
|
||||
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
if((address & 0x0000F000) != 0x0000F000){
|
||||
dbvzSetBusErrorTimeOut(address, false);
|
||||
@@ -529,16 +520,6 @@ uint16_t dbvzGetRegister16(uint32_t address){
|
||||
}
|
||||
|
||||
case UTX1:{
|
||||
#if defined(EMU_DEBUG)
|
||||
printHwRegAccess(address, 0, 16, false);
|
||||
#endif
|
||||
uint16_t dataFlag = 0;
|
||||
if (palmIrDataSize != NULL)
|
||||
if (palmIrDataSize() > 0) {
|
||||
dataFlag = 0x4000; // byte swapped
|
||||
updateUart1Interrupt();
|
||||
}
|
||||
|
||||
uint16_t uart1TxStatus = registerArrayRead16(UTX1);
|
||||
uint8_t entrys = uart1TxFifoEntrys();
|
||||
|
||||
@@ -546,20 +527,10 @@ uint16_t dbvzGetRegister16(uint32_t address){
|
||||
uart1TxStatus |= (entrys < 4) << 14;
|
||||
uart1TxStatus |= (entrys < 8) << 13;
|
||||
|
||||
return uart1TxStatus | dataFlag;
|
||||
return uart1TxStatus;
|
||||
}
|
||||
|
||||
case UTX2:{
|
||||
#if defined(EMU_DEBUG)
|
||||
printHwRegAccess(address, 0, 16, false);
|
||||
#endif
|
||||
uint16_t dataFlag = 0;
|
||||
if (palmSerialDataSize != NULL)
|
||||
if (palmSerialDataSize() > 0) {
|
||||
dataFlag = 0x4000; // byte swapped
|
||||
updateUart2Interrupt();
|
||||
}
|
||||
|
||||
uint16_t uart2TxStatus = registerArrayRead16(UTX2);
|
||||
uint8_t entrys = uart2TxFifoEntrys();
|
||||
|
||||
@@ -567,7 +538,7 @@ uint16_t dbvzGetRegister16(uint32_t address){
|
||||
uart2TxStatus |= (entrys < 4) << 14;
|
||||
uart2TxStatus |= (entrys < 8) << 13;
|
||||
|
||||
return uart2TxStatus | dataFlag;
|
||||
return uart2TxStatus;
|
||||
}
|
||||
|
||||
case PLLFSR:
|
||||
@@ -628,12 +599,11 @@ uint16_t dbvzGetRegister16(uint32_t address){
|
||||
return registerArrayRead16(address);
|
||||
|
||||
default:
|
||||
printHwRegAccess(address, 0, 16, false);
|
||||
|
||||
//bootloader
|
||||
if(address >= 0xE00)
|
||||
return registerArrayRead16(address);
|
||||
|
||||
printHwRegAccess(address, 0, 16, false);
|
||||
return 0x0000;
|
||||
}
|
||||
}
|
||||
@@ -698,7 +668,6 @@ void dbvzSetRegister8(uint32_t address, uint8_t value){
|
||||
if((registerArrayRead16(USTCNT2) & 0xA000) == 0xA000){
|
||||
uart2TxFifoWrite(value);
|
||||
updateUart2Interrupt();
|
||||
updateUart2PortState();
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -1159,7 +1128,6 @@ void dbvzSetRegister16(uint32_t address, uint16_t value){
|
||||
if((registerArrayRead16(USTCNT2) & 0xA000) == 0xA000){
|
||||
uart2TxFifoWrite(value & 0x1000 ? value & 0xFF : EMU_SERIAL_BREAK);
|
||||
updateUart2Interrupt();
|
||||
updateUart2PortState();
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
@@ -710,7 +710,6 @@ static void setUstcnt2(uint16_t value){
|
||||
|
||||
registerArrayWrite16(USTCNT2, value);
|
||||
updateUart2Interrupt();
|
||||
updateUart2PortState();
|
||||
}
|
||||
|
||||
static void setTstat1(uint16_t value){
|
||||
@@ -404,9 +404,6 @@ static void dbvzEndClk32(void){
|
||||
updateUart1Interrupt();
|
||||
updateUart2Interrupt();
|
||||
|
||||
updateUart1PortState();
|
||||
updateUart2PortState();
|
||||
|
||||
checkInterrupts();
|
||||
}
|
||||
|
||||
135
src/emulator.c
135
src/emulator.c
@@ -11,7 +11,6 @@
|
||||
#include "ads7846.h"
|
||||
#include "pdiUsbD12.h"
|
||||
#include "sdCard.h"
|
||||
#include "serial.h"
|
||||
#include "silkscreen.h"
|
||||
#include "portability.h"
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
@@ -78,50 +77,7 @@ void (*palmSerialDataFlush)(void);//called by the emulator to delete all da
|
||||
void (*palmGetRtcFromHost)(uint8_t* writeBack);//[0] = hours, [1] = minutes, [2] = seconds
|
||||
|
||||
|
||||
static void patchOsRom(uint32_t address, char* patch){
|
||||
uint32_t offset;
|
||||
uint32_t patchBytes = strlen(patch) / 2;//1 char per nibble
|
||||
uint32_t swapBegin = address & 0xFFFFFFFE;
|
||||
uint32_t swapSize = patchBytes / sizeof(uint16_t) + 1;
|
||||
char conv[5] = "0xXX";
|
||||
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
if(!palmEmulatingTungstenT3)
|
||||
#endif
|
||||
swap16BufferIfLittle(&palmRom[swapBegin], swapSize);
|
||||
for(offset = 0; offset < patchBytes; offset++){
|
||||
conv[2] = patch[offset * 2];
|
||||
conv[3] = patch[offset * 2 + 1];
|
||||
palmRom[address + offset] = strtol(conv, NULL, 0);
|
||||
}
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
if(!palmEmulatingTungstenT3)
|
||||
#endif
|
||||
swap16BufferIfLittle(&palmRom[swapBegin], swapSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the initial RAM with garbage.
|
||||
*
|
||||
* @param ram The RAM to fill.
|
||||
* @param size The size of RAM.
|
||||
* @since 2024/06/14
|
||||
*/
|
||||
void mu_garbage_fill(uint8_t* ram, uint32_t size) {
|
||||
uint32_t i;
|
||||
uint8_t vis;
|
||||
|
||||
vis = 179;
|
||||
for (i = 0; i < size; i++) {
|
||||
ram[i] = vis;
|
||||
vis = ((vis << 1) | ((vis >> 7) & 1)) ^ 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
uint32_t palmRomSize, uint8_t *palmBootloaderData,
|
||||
uint32_t palmBootloaderSize, bool syncRtc,
|
||||
bool allowInvalidBehavior, const char *serialPortDev) {
|
||||
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t palmRomSize, uint8_t* palmBootloaderData, uint32_t palmBootloaderSize, bool syncRtc, bool allowInvalidBehavior){
|
||||
if(emulatorInitialized)
|
||||
return EMU_ERROR_RESOURCE_LOCKED;
|
||||
|
||||
@@ -136,40 +92,35 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
palmIrDataReceive = NULL;
|
||||
palmIrDataSend = NULL;
|
||||
palmIrDataFlush = NULL;
|
||||
palmSerialSetPortProperties = NULL;
|
||||
palmSerialDataSize = NULL;
|
||||
palmSerialDataReceive = NULL;
|
||||
palmSerialDataSend = NULL;
|
||||
palmSerialDataFlush = NULL;
|
||||
palmGetRtcFromHost = NULL;
|
||||
|
||||
// Setup serial port
|
||||
palmSerialSetPortProperties = NULL;
|
||||
palmSerialDataSize = NULL;
|
||||
palmSerialDataReceive = NULL;
|
||||
palmSerialDataSend = NULL;
|
||||
palmSerialDataFlush = NULL;
|
||||
|
||||
if (serialPortDev != NULL) {
|
||||
mu_serial_open_and_init(serialPortDev);
|
||||
}
|
||||
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
palmEmulatingTungstenT3 = emulatedDevice == EMU_DEVICE_TUNGSTEN_T3;
|
||||
|
||||
if(palmEmulatingTungstenT3){
|
||||
//emulating Tungsten T3
|
||||
bool dynarecInited = false;
|
||||
|
||||
dynarecInited = pxa260Init(&palmRom, &palmRam);
|
||||
palmRom = malloc(TUNGSTEN_T3_ROM_SIZE);
|
||||
palmRam = malloc(TUNGSTEN_T3_RAM_SIZE);
|
||||
palmFramebuffer = malloc(320 * 480 * sizeof(uint16_t));
|
||||
palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
|
||||
palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
|
||||
if(!palmFramebuffer || !palmAudio || !palmAudioResampler || !dynarecInited){
|
||||
if(!palmRom || !palmRam || !palmFramebuffer || !palmAudio || !palmAudioResampler){
|
||||
free(palmRom);
|
||||
free(palmRam);
|
||||
free(palmFramebuffer);
|
||||
free(palmAudio);
|
||||
blip_delete(palmAudioResampler);
|
||||
pxa260Deinit();
|
||||
return EMU_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(palmRom, palmRomData, FAST_MIN(palmRomSize, TUNGSTEN_T3_ROM_SIZE));
|
||||
if(palmRomSize < TUNGSTEN_T3_ROM_SIZE)
|
||||
memset(palmRom + palmRomSize, 0x00, TUNGSTEN_T3_ROM_SIZE - palmRomSize);
|
||||
swap32BufferIfBig(palmRom, TUNGSTEN_T3_ROM_SIZE / sizeof(uint32_t));
|
||||
memset(palmRam, 0x00, TUNGSTEN_T3_RAM_SIZE);
|
||||
memset(palmFramebuffer, 0x00, 320 * 480 * sizeof(uint16_t));//TODO:PXA260 code doesnt always output a picture like my SED1376 code, so clear the buffer to prevent garbage from being displayed before the first render
|
||||
memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
|
||||
@@ -186,9 +137,6 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
pxa260Framebuffer = palmFramebuffer;
|
||||
blip_set_rates(palmAudioResampler, DBVZ_AUDIO_MAX_CLOCK_RATE, AUDIO_SAMPLE_RATE);
|
||||
|
||||
patchOsRom(0x333EC6, "0000");//blocks out the slot driver
|
||||
patchOsRom(0x205C, "0000A0E1");//blocks idle loop jump with NOP
|
||||
|
||||
//reset everything
|
||||
emulatorSoftReset();
|
||||
pxa260SetRtc(0, 0, 0, 0);
|
||||
@@ -200,9 +148,7 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
|
||||
//allocate buffers, add 4 to memory regions to prevent SIGSEGV from accessing off the end
|
||||
palmRom = malloc(M5XX_ROM_SIZE + 4);
|
||||
|
||||
palmRam = malloc((emulatorGetRamSize()) + 4);
|
||||
|
||||
palmRam = malloc((palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) + 4);
|
||||
palmFramebuffer = malloc(160 * 220 * sizeof(uint16_t));
|
||||
palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
|
||||
palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
|
||||
@@ -220,10 +166,7 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
if(palmRomSize < M5XX_ROM_SIZE)
|
||||
memset(palmRom + palmRomSize, 0x00, M5XX_ROM_SIZE - palmRomSize);
|
||||
swap16BufferIfLittle(palmRom, M5XX_ROM_SIZE / sizeof(uint16_t));
|
||||
|
||||
memset(palmRam, 0x00, emulatorGetRamSize());
|
||||
mu_garbage_fill(palmRam, emulatorGetRamSize());
|
||||
|
||||
memset(palmRam, 0x00, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
|
||||
dbvzLoadBootloader(palmBootloaderData, palmBootloaderSize);
|
||||
memcpy(palmFramebuffer + 160 * 160, silkscreen160x60, 160 * 60 * sizeof(uint16_t));
|
||||
memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
|
||||
@@ -263,21 +206,11 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
|
||||
void emulatorDeinit(void){
|
||||
if(emulatorInitialized){
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
if(!palmEmulatingTungstenT3){
|
||||
#endif
|
||||
free(palmRom);
|
||||
free(palmRam);
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
}
|
||||
#endif
|
||||
free(palmRom);
|
||||
free(palmRam);
|
||||
free(palmFramebuffer);
|
||||
free(palmAudio);
|
||||
blip_delete(palmAudioResampler);
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
if(palmEmulatingTungstenT3)
|
||||
pxa260Deinit();
|
||||
#endif
|
||||
free(palmSdCard.flashChipData);
|
||||
emulatorInitialized = false;
|
||||
}
|
||||
@@ -294,7 +227,7 @@ void emulatorHardReset(void){
|
||||
}
|
||||
else{
|
||||
#endif
|
||||
memset(palmRam, 0x00, emulatorGetRamSize());
|
||||
memset(palmRam, 0x00, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
|
||||
emulatorSoftReset();
|
||||
sdCardReset();
|
||||
dbvzSetRtc(0, 0, 0, 0);
|
||||
@@ -362,7 +295,7 @@ uint32_t emulatorGetStateSize(void){
|
||||
size += sed1376StateSize();
|
||||
size += ads7846StateSize();
|
||||
size += pdiUsbD12StateSize();
|
||||
size += emulatorGetRamSize();//system RAM buffer
|
||||
size += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;//system RAM buffer
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
}
|
||||
#endif
|
||||
@@ -417,6 +350,7 @@ bool emulatorSaveState(uint8_t* data, uint32_t size){
|
||||
|
||||
//memory
|
||||
memcpy(data + offset, palmRam, TUNGSTEN_T3_RAM_SIZE);
|
||||
swap32BufferIfBig(data + offset, TUNGSTEN_T3_ROM_SIZE / sizeof(uint32_t));
|
||||
offset += TUNGSTEN_T3_RAM_SIZE;
|
||||
}
|
||||
else{
|
||||
@@ -434,9 +368,9 @@ bool emulatorSaveState(uint8_t* data, uint32_t size){
|
||||
offset += pdiUsbD12StateSize();
|
||||
|
||||
//memory
|
||||
memcpy(data + offset, palmRam, emulatorGetRamSize());
|
||||
swap16BufferIfLittle(data + offset, (emulatorGetRamSize()) / sizeof(uint16_t));
|
||||
offset += emulatorGetRamSize();
|
||||
memcpy(data + offset, palmRam, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
|
||||
swap16BufferIfLittle(data + offset, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
|
||||
offset += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
}
|
||||
#endif
|
||||
@@ -541,6 +475,7 @@ bool emulatorLoadState(uint8_t* data, uint32_t size){
|
||||
|
||||
//memory
|
||||
memcpy(palmRam, data + offset, TUNGSTEN_T3_RAM_SIZE);
|
||||
swap32BufferIfBig(palmRam, TUNGSTEN_T3_ROM_SIZE / sizeof(uint32_t));
|
||||
offset += TUNGSTEN_T3_RAM_SIZE;
|
||||
}
|
||||
else{
|
||||
@@ -558,9 +493,9 @@ bool emulatorLoadState(uint8_t* data, uint32_t size){
|
||||
offset += pdiUsbD12StateSize();
|
||||
|
||||
//memory
|
||||
memcpy(palmRam, data + offset, emulatorGetRamSize());
|
||||
swap16BufferIfLittle(palmRam, (emulatorGetRamSize()) / sizeof(uint16_t));
|
||||
offset += emulatorGetRamSize();
|
||||
memcpy(palmRam, data + offset, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
|
||||
swap16BufferIfLittle(palmRam, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
|
||||
offset += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
}
|
||||
#endif
|
||||
@@ -640,9 +575,7 @@ uint32_t emulatorGetRamSize(void){
|
||||
if(palmEmulatingTungstenT3)
|
||||
return TUNGSTEN_T3_RAM_SIZE;
|
||||
#endif
|
||||
if (palmEmulatingM500)
|
||||
return M500_RAM_SIZE;
|
||||
return M515_RAM_SIZE;
|
||||
return palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
|
||||
}
|
||||
|
||||
bool emulatorSaveRam(uint8_t* data, uint32_t size){
|
||||
@@ -652,14 +585,15 @@ bool emulatorSaveRam(uint8_t* data, uint32_t size){
|
||||
return false;
|
||||
|
||||
memcpy(data, palmRam, TUNGSTEN_T3_RAM_SIZE);
|
||||
swap32BufferIfBig(data, TUNGSTEN_T3_ROM_SIZE / sizeof(uint32_t));
|
||||
}
|
||||
else{
|
||||
#endif
|
||||
if(size < (emulatorGetRamSize()))
|
||||
if(size < (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE))
|
||||
return false;
|
||||
|
||||
memcpy(data, palmRam, emulatorGetRamSize());
|
||||
swap16BufferIfLittle(data, (emulatorGetRamSize()) / sizeof(uint16_t));
|
||||
memcpy(data, palmRam, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
|
||||
swap16BufferIfLittle(data, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
}
|
||||
#endif
|
||||
@@ -674,14 +608,15 @@ bool emulatorLoadRam(uint8_t* data, uint32_t size){
|
||||
return false;
|
||||
|
||||
memcpy(palmRam, data, TUNGSTEN_T3_RAM_SIZE);
|
||||
swap32BufferIfBig(palmRam, TUNGSTEN_T3_ROM_SIZE / sizeof(uint32_t));
|
||||
}
|
||||
else{
|
||||
#endif
|
||||
if(size < (emulatorGetRamSize()))
|
||||
if(size < (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE))
|
||||
return false;
|
||||
|
||||
memcpy(palmRam, data, emulatorGetRamSize());
|
||||
swap16BufferIfLittle(palmRam, (emulatorGetRamSize()) / sizeof(uint16_t));
|
||||
memcpy(palmRam, data, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
|
||||
swap16BufferIfLittle(palmRam, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
|
||||
#if defined(EMU_SUPPORT_PALM_OS5)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -45,15 +45,13 @@ static void debugLog(char* str, ...){};
|
||||
//config options
|
||||
#define EMU_FPS 60
|
||||
#define DBVZ_SYSCLK_PRECISION 2000000//the amount of cycles to run before adding SYSCLKs, higher = faster, higher values may skip timer events and lower audio accuracy
|
||||
|
||||
#define AUDIO_SAMPLE_RATE 48000
|
||||
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLE_RATE / EMU_FPS)
|
||||
|
||||
#define AUDIO_SPEAKER_RANGE 0x6000//prevent hitting the top or bottom of the speaker when switching direction rapidly
|
||||
#define SD_CARD_NCR_BYTES 1//how many 0xFF bytes come before the R1 response
|
||||
#define SAVE_STATE_VERSION 0x00000001
|
||||
|
||||
//shared constants
|
||||
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLE_RATE / EMU_FPS)
|
||||
#define SD_CARD_BLOCK_SIZE 512//all newer SDSC cards have this fixed at 512
|
||||
#define SD_CARD_BLOCK_DATA_PACKET_SIZE (1 + SD_CARD_BLOCK_SIZE + 2)
|
||||
#define SD_CARD_RESPONSE_FIFO_SIZE (SD_CARD_BLOCK_DATA_PACKET_SIZE * 3)
|
||||
@@ -109,7 +107,7 @@ enum{
|
||||
};
|
||||
|
||||
//types
|
||||
typedef struct {
|
||||
typedef struct{
|
||||
bool enable;
|
||||
bool enableParity;
|
||||
bool oddParity;
|
||||
@@ -215,11 +213,7 @@ extern void (*palmSerialDataFlush)(void);//called by the emulator to delete
|
||||
extern void (*palmGetRtcFromHost)(uint8_t* writeBack);//[0] = hours, [1] = minutes, [2] = seconds
|
||||
|
||||
//functions
|
||||
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
|
||||
uint32_t palmRomSize, uint8_t *palmBootloaderData,
|
||||
uint32_t palmBootloaderSize, bool syncRtc,
|
||||
bool allowInvalidBehavior, const char *serialPortDev);
|
||||
|
||||
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t palmRomSize, uint8_t* palmBootloaderData, uint32_t palmBootloaderSize, bool syncRtc, bool allowInvalidBehavior);
|
||||
void emulatorDeinit(void);
|
||||
void emulatorHardReset(void);
|
||||
void emulatorSoftReset(void);
|
||||
@@ -1,12 +0,0 @@
|
||||
# m68k Module
|
||||
add_library(MuCoreFileLauncher STATIC
|
||||
launcher.c)
|
||||
|
||||
# Make this position independent so it can be linked into shared libraries
|
||||
set_property(TARGET MuCoreFileLauncher
|
||||
PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Includes for the project
|
||||
target_include_directories(MuCoreFileLauncher PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/include")
|
||||
@@ -3,12 +3,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "emulator.h"
|
||||
#include "portability.h"
|
||||
#include "m68k/m68k.h"
|
||||
#include "m68k/m68kcpu.h"
|
||||
#include "dbvz.h"
|
||||
#include "fileLauncher/launcher.h"
|
||||
#include "../emulator.h"
|
||||
#include "../portability.h"
|
||||
#include "../m68k/m68k.h"
|
||||
#include "../m68k/m68kcpu.h"
|
||||
#include "../dbvz.h"
|
||||
#include "launcher.h"
|
||||
|
||||
|
||||
typedef struct{
|
||||
|
||||
0
include/flx68000.h → src/flx68000.h
Normal file → Executable file
0
include/flx68000.h → src/flx68000.h
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user