12 Commits

Author SHA1 Message Date
meepingsnesroms
2b39468a32 Add divide function tests 2020-01-20 15:55:24 -08:00
meepingsnesroms
c33be1988d Update readme.md 2019-12-28 14:19:08 -08:00
meepingsnesroms
82aa0c6fc0 Clean up main makefile 2019-12-28 13:06:14 -08:00
meepingsnesroms
018ed97874 OS 5 now outputting a framebuffer 2019-12-28 12:16:48 -08:00
meepingsnesroms
be43d3a39a Clean up dynarec mess
Will deal with speed later, just need it to boot for now.
2019-12-15 00:03:02 -08:00
meepingsnesroms
ee822d2800 Lock up bug seems fixed 2019-12-14 22:10:03 -08:00
meepingsnesroms
46918f8d0f Update CPU_2.c 2019-12-10 00:18:10 -08:00
meepingsnesroms
5601f0c3d4 Fixes, change logging 2019-12-10 00:06:59 -08:00
meepingsnesroms
349ff5d92f Update idleModeStackTrace.txt 2019-12-07 10:38:47 -08:00
meepingsnesroms
be02f9b313 Log all attempts at setting the PC, capture where the CPU idle error occurs 2019-12-05 23:56:00 -08:00
meepingsnesroms
87f5312954 Remove ? from window bar, debugging stuff 2019-12-05 13:38:01 -08:00
meepingsnesroms
34426a791b Add a way to capture function calls reliably 2019-11-29 16:25:59 -08:00
176 changed files with 3456 additions and 22276 deletions

15
.circleci/config.yml Normal file
View 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
View File

@@ -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

View File

@@ -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
View File

2
.idea/Mu.iml generated
View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

19
.idea/misc.xml generated
View File

@@ -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
View File

@@ -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
View File

@@ -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>

View File

@@ -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
View File

@@ -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/.

View File

@@ -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)

View 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)

View 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)

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +0,0 @@
#ifndef H_ARMSNIPPETS
#define H_ARMSNIPPETS
#define armloader_cb()
#endif

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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),)

View File

@@ -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),)

View File

@@ -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),)

View File

@@ -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),)

View File

@@ -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),)

View File

@@ -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),)

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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."

View File

@@ -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()

View File

@@ -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()

View File

@@ -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 \

View File

@@ -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

View File

@@ -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();

View File

@@ -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());

View File

@@ -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());
}

View File

@@ -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;

View File

@@ -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">

View File

@@ -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);

View File

@@ -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"

View File

@@ -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)

View File

@@ -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)

View File

@@ -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")

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 = &REG0;
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;
}
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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")

View File

@@ -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>

View File

@@ -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;

View File

@@ -710,7 +710,6 @@ static void setUstcnt2(uint16_t value){
registerArrayWrite16(USTCNT2, value);
updateUart2Interrupt();
updateUart2PortState();
}
static void setTstat1(uint16_t value){

View File

@@ -404,9 +404,6 @@ static void dbvzEndClk32(void){
updateUart1Interrupt();
updateUart2Interrupt();
updateUart1PortState();
updateUart2PortState();
checkInterrupts();
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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")

View File

@@ -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
View File

Some files were not shown because too many files have changed in this diff Show More