mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
ppc-7.0 queue
* Exception model rework (Fabiano) * Unused CPU models removal (Fabiano and Cédric) * Fix for VOF installation (Alexey) * Misc fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmIFDBsACgkQUaNDx8/7 7KHmmg//RjCaqbubw8nc58stxGvwf30tcLzPKbQzoz4rZ/hxMaXDKTzh7BA16qJO fJDrnQCcYa1dpLWXCygY/5G7+DbaGYRava/3BqBv2qAO0wDdKbnxKGuFSSbqgeca skTQK1R5hSYclFNI13yFLJrAkwiTSZjI+UhCkUqW6wZS1qeZ1ClBwoCMIZ8dP4vE cshD78lFRSCLhScrhhQqeQymEWk6eUmv4TY2gSiVpCZCaR1wlXxy3/YOd5i2w2B1 A+JAwvCOknKaGzCftbZN0Po8orcdXyQ96YZNQxjL9Wu58zZllqzolF2pJi0Qph2h 3ZW7Bw3BbnUl6ceWg/J/e+gVkGLKyPGJ6eD556HxccJZPXgtEC8QyP8ACzl3mJ1E 13abW4yX7XwtgmVoXQQu0vaKKM4AamIkqYgn/kGP1TQO5s+CMf61+WYy1HzIio1Z 9jUhpRWBiEsuhigy/kFejU9dYVHYJ0rcr7pwRa+Nhet+8Rzv5Klr6rQExsftkZmc 0KcJDhpGVrmdO/qU8BYh/lhyOvx9+9qI8gG/g2PJtR4VSTHRUqxZ+VzuIC2tVpD0 XJnCNSBgJs59kybPX3Pn1f8BmVoZBq+oJBScrOJne3finBbxioo4JiKReBD12y1A LxE+JTV0N/aPjkMzuw+VXPMZ1suxrd2doiyDKXv/eijleGtdsPg= =/0n8 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/legoater/tags/pull-ppc-20220210' into staging ppc-7.0 queue * Exception model rework (Fabiano) * Unused CPU models removal (Fabiano and Cédric) * Fix for VOF installation (Alexey) * Misc fixes # gpg: Signature made Thu 10 Feb 2022 12:59:07 GMT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * remotes/legoater/tags/pull-ppc-20220210: (42 commits) spapr/vof: Install rom and nvram binaries docs: rstfy confidential guest documentation target/ppc: Change VSX instructions behavior to fill with zeros target/ppc: books: Remove excp_model argument from ppc_excp_apply_ail target/ppc: Assert if MSR bits differ from msr_mask during exceptions target/ppc: powerpc_excp: Move common code to the caller function target/ppc: Remove powerpc_excp_legacy target/ppc: 7xx: Set SRRs directly in exception code target/ppc: 7xx: Software TLB cleanup target/ppc: 7xx: System Reset cleanup target/ppc: 7xx: System Call exception cleanup target/ppc: 7xx: Program exception cleanup target/ppc: 7xx: External interrupt cleanup target/ppc: 7xx: Machine Check exception cleanup target/ppc: Simplify powerpc_excp_7xx target/ppc: Introduce powerpc_excp_7xx target/ppc: Merge 7x5 and 7x0 exception model IDs target/ppc: 6xx: Set SRRs directly in exception code target/ppc: 6xx: Software TLB exceptions cleanup target/ppc: 6xx: System Reset interrupt cleanup ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
cc5ce8b8b6
32 changed files with 717 additions and 2375 deletions
|
@ -408,7 +408,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
|
|||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: docs/amd-memory-encryption.txt
|
||||
F: docs/system/i386/amd-memory-encryption.rst
|
||||
F: docs/system/i386/sgx.rst
|
||||
F: target/i386/kvm/
|
||||
F: target/i386/sev*
|
||||
|
|
|
@ -19,10 +19,10 @@ Running a Confidential Guest
|
|||
|
||||
To run a confidential guest you need to add two command line parameters:
|
||||
|
||||
1. Use "-object" to create a "confidential guest support" object. The
|
||||
1. Use ``-object`` to create a "confidential guest support" object. The
|
||||
type and parameters will vary with the specific mechanism to be
|
||||
used
|
||||
2. Set the "confidential-guest-support" machine parameter to the ID of
|
||||
2. Set the ``confidential-guest-support`` machine parameter to the ID of
|
||||
the object from (1).
|
||||
|
||||
Example (for AMD SEV)::
|
||||
|
@ -37,13 +37,8 @@ Supported mechanisms
|
|||
|
||||
Currently supported confidential guest mechanisms are:
|
||||
|
||||
AMD Secure Encrypted Virtualization (SEV)
|
||||
docs/amd-memory-encryption.txt
|
||||
|
||||
POWER Protected Execution Facility (PEF)
|
||||
docs/papr-pef.txt
|
||||
|
||||
s390x Protected Virtualization (PV)
|
||||
docs/system/s390x/protvirt.rst
|
||||
* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
|
||||
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
|
||||
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
|
||||
|
||||
Other mechanisms may be supported in future.
|
|
@ -1,3 +1,6 @@
|
|||
AMD Secure Encrypted Virtualization (SEV)
|
||||
=========================================
|
||||
|
||||
Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
|
||||
|
||||
SEV is an extension to the AMD-V architecture which supports running encrypted
|
||||
|
@ -24,17 +27,18 @@ the hypervisor to satisfy the requested function.
|
|||
|
||||
Launching
|
||||
---------
|
||||
|
||||
Boot images (such as bios) must be encrypted before a guest can be booted. The
|
||||
MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images: LAUNCH_START,
|
||||
LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
|
||||
``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images: ``LAUNCH_START``,
|
||||
``LAUNCH_UPDATE_DATA``, ``LAUNCH_MEASURE`` and ``LAUNCH_FINISH``. These four commands
|
||||
together generate a fresh memory encryption key for the VM, encrypt the boot
|
||||
images and provide a measurement than can be used as an attestation of a
|
||||
successful launch.
|
||||
|
||||
For a SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to encrypt the
|
||||
For a SEV-ES guest, the ``LAUNCH_UPDATE_VMSA`` command is also used to encrypt the
|
||||
guest register state, or VM save area (VMSA), for all of the guest vCPUs.
|
||||
|
||||
LAUNCH_START is called first to create a cryptographic launch context within
|
||||
``LAUNCH_START`` is called first to create a cryptographic launch context within
|
||||
the firmware. To create this context, guest owner must provide a guest policy,
|
||||
its public Diffie-Hellman key (PDH) and session parameters. These inputs
|
||||
should be treated as a binary blob and must be passed as-is to the SEV firmware.
|
||||
|
@ -45,37 +49,37 @@ in bad measurement). The guest policy is a 4-byte data structure containing
|
|||
several flags that restricts what can be done on a running SEV guest.
|
||||
See KM Spec section 3 and 6.2 for more details.
|
||||
|
||||
The guest policy can be provided via the 'policy' property (see below)
|
||||
The guest policy can be provided via the ``policy`` property::
|
||||
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,policy=0x1...\
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,policy=0x1...\
|
||||
|
||||
Setting the "SEV-ES required" policy bit (bit 2) will launch the guest as a
|
||||
SEV-ES guest (see below)
|
||||
SEV-ES guest::
|
||||
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,policy=0x5...\
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,policy=0x5...\
|
||||
|
||||
The guest owner provided DH certificate and session parameters will be used to
|
||||
establish a cryptographic session with the guest owner to negotiate keys used
|
||||
for the attestation.
|
||||
|
||||
The DH certificate and session blob can be provided via the 'dh-cert-file' and
|
||||
'session-file' properties (see below)
|
||||
The DH certificate and session blob can be provided via the ``dh-cert-file`` and
|
||||
``session-file`` properties::
|
||||
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
|
||||
# ${QEMU} \
|
||||
sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
|
||||
|
||||
LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
|
||||
created via the LAUNCH_START command. If required, this command can be called
|
||||
``LAUNCH_UPDATE_DATA`` encrypts the memory region using the cryptographic context
|
||||
created via the ``LAUNCH_START`` command. If required, this command can be called
|
||||
multiple times to encrypt different memory regions. The command also calculates
|
||||
the measurement of the memory contents as it encrypts.
|
||||
|
||||
LAUNCH_UPDATE_VMSA encrypts all the vCPU VMSAs for a SEV-ES guest using the
|
||||
cryptographic context created via the LAUNCH_START command. The command also
|
||||
``LAUNCH_UPDATE_VMSA`` encrypts all the vCPU VMSAs for a SEV-ES guest using the
|
||||
cryptographic context created via the ``LAUNCH_START`` command. The command also
|
||||
calculates the measurement of the VMSAs as it encrypts them.
|
||||
|
||||
LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory and,
|
||||
``LAUNCH_MEASURE`` can be used to retrieve the measurement of encrypted memory and,
|
||||
for a SEV-ES guest, encrypted VMSAs. This measurement is a signature of the
|
||||
memory contents and, for a SEV-ES guest, the VMSA contents, that can be sent
|
||||
to the guest owner as an attestation that the memory and VMSAs were encrypted
|
||||
|
@ -85,27 +89,28 @@ Since the guest owner knows the initial contents of the guest at boot, the
|
|||
attestation measurement can be verified by comparing it to what the guest owner
|
||||
expects.
|
||||
|
||||
LAUNCH_FINISH finalizes the guest launch and destroys the cryptographic
|
||||
``LAUNCH_FINISH`` finalizes the guest launch and destroys the cryptographic
|
||||
context.
|
||||
|
||||
See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
|
||||
See SEV KM API Spec ([SEVKM]_) 'Launching a guest' usage flow (Appendix A) for the
|
||||
complete flow chart.
|
||||
|
||||
To launch a SEV guest
|
||||
To launch a SEV guest::
|
||||
|
||||
# ${QEMU} \
|
||||
-machine ...,confidential-guest-support=sev0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
|
||||
# ${QEMU} \
|
||||
-machine ...,confidential-guest-support=sev0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
|
||||
|
||||
To launch a SEV-ES guest
|
||||
To launch a SEV-ES guest::
|
||||
|
||||
# ${QEMU} \
|
||||
-machine ...,confidential-guest-support=sev0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x5
|
||||
# ${QEMU} \
|
||||
-machine ...,confidential-guest-support=sev0 \
|
||||
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x5
|
||||
|
||||
An SEV-ES guest has some restrictions as compared to a SEV guest. Because the
|
||||
guest register state is encrypted and cannot be updated by the VMM/hypervisor,
|
||||
a SEV-ES guest:
|
||||
|
||||
- Does not support SMM - SMM support requires updating the guest register
|
||||
state.
|
||||
- Does not support reboot - a system reset requires updating the guest register
|
||||
|
@ -114,35 +119,42 @@ a SEV-ES guest:
|
|||
manage booting APs.
|
||||
|
||||
Debugging
|
||||
-----------
|
||||
---------
|
||||
|
||||
Since the memory contents of a SEV guest are encrypted, hypervisor access to
|
||||
the guest memory will return cipher text. If the guest policy allows debugging,
|
||||
then a hypervisor can use the DEBUG_DECRYPT and DEBUG_ENCRYPT commands to access
|
||||
the guest memory region for debug purposes. This is not supported in QEMU yet.
|
||||
|
||||
Snapshot/Restore
|
||||
-----------------
|
||||
----------------
|
||||
|
||||
TODO
|
||||
|
||||
Live Migration
|
||||
----------------
|
||||
---------------
|
||||
|
||||
TODO
|
||||
|
||||
References
|
||||
-----------------
|
||||
----------
|
||||
|
||||
AMD Memory Encryption whitepaper:
|
||||
https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
|
||||
`AMD Memory Encryption whitepaper
|
||||
<https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf>`_
|
||||
|
||||
Secure Encrypted Virtualization Key Management:
|
||||
[1] http://developer.amd.com/wordpress/media/2017/11/55766_SEV-KM-API_Specification.pdf
|
||||
.. [SEVKM] `Secure Encrypted Virtualization Key Management
|
||||
<http://developer.amd.com/wordpress/media/2017/11/55766_SEV-KM-API_Specification.pdf>`_
|
||||
|
||||
KVM Forum slides:
|
||||
http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
|
||||
https://www.linux-kvm.org/images/9/94/Extending-Secure-Encrypted-Virtualization-with-SEV-ES-Thomas-Lendacky-AMD.pdf
|
||||
|
||||
AMD64 Architecture Programmer's Manual:
|
||||
http://support.amd.com/TechDocs/24593.pdf
|
||||
SME is section 7.10
|
||||
SEV is section 15.34
|
||||
SEV-ES is section 15.35
|
||||
* `AMD’s Virtualization Memory Encryption (2016)
|
||||
<http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf>`_
|
||||
* `Extending Secure Encrypted Virtualization With SEV-ES (2018)
|
||||
<https://www.linux-kvm.org/images/9/94/Extending-Secure-Encrypted-Virtualization-with-SEV-ES-Thomas-Lendacky-AMD.pdf>`_
|
||||
|
||||
`AMD64 Architecture Programmer's Manual:
|
||||
<http://support.amd.com/TechDocs/24593.pdf>`_
|
||||
|
||||
* SME is section 7.10
|
||||
* SEV is section 15.34
|
||||
* SEV-ES is section 15.35
|
|
@ -34,3 +34,4 @@ or Hypervisor.Framework.
|
|||
targets
|
||||
security
|
||||
multi-process
|
||||
confidential-guest-support
|
||||
|
|
|
@ -224,6 +224,8 @@ nested. Combinations not shown in the table are not available.
|
|||
.. [3] Introduced on Power10 machines.
|
||||
|
||||
|
||||
.. _power-papr-protected-execution-facility-pef:
|
||||
|
||||
POWER (PAPR) Protected Execution Facility (PEF)
|
||||
-----------------------------------------------
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ Architectural features
|
|||
i386/cpu
|
||||
i386/kvm-pv
|
||||
i386/sgx
|
||||
i386/amd-memory-encryption
|
||||
|
||||
.. _pcsys_005freq:
|
||||
|
||||
|
|
21
hw/ppc/ppc.c
21
hw/ppc/ppc.c
|
@ -1083,27 +1083,6 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
|||
return &cpu_ppc_set_tb_clk;
|
||||
}
|
||||
|
||||
/* Specific helpers for POWER & PowerPC 601 RTC */
|
||||
void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
|
||||
{
|
||||
_cpu_ppc_store_tbu(env, value);
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
|
||||
{
|
||||
return _cpu_ppc_load_tbu(env);
|
||||
}
|
||||
|
||||
void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
|
||||
{
|
||||
cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
|
||||
{
|
||||
return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PowerPC 40x timers */
|
||||
|
||||
|
|
|
@ -255,13 +255,8 @@ static void ibm_40p_init(MachineState *machine)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (env->flags & POWERPC_FLAG_RTC_CLK) {
|
||||
/* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
|
||||
cpu_ppc_tb_init(env, 7812500UL);
|
||||
} else {
|
||||
/* Set time-base frequency to 100 Mhz */
|
||||
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
|
||||
}
|
||||
/* Set time-base frequency to 100 Mhz */
|
||||
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
|
||||
qemu_register_reset(ppc_prep_reset, cpu);
|
||||
|
||||
/* PCI host */
|
||||
|
|
|
@ -54,14 +54,6 @@ uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
|
|||
return cpu_ppc_get_tb(env);
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
|
||||
__attribute__ (( alias ("cpu_ppc_load_tbu") ));
|
||||
|
||||
uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
|
||||
{
|
||||
return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
|
||||
}
|
||||
|
||||
/* XXX: to be fixed */
|
||||
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
|
||||
{
|
||||
|
@ -289,14 +281,6 @@ void cpu_loop(CPUPPCState *env)
|
|||
cpu_abort(cs, "Programmable interval timer interrupt "
|
||||
"while in user mode. Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_IO: /* IO error exception */
|
||||
cpu_abort(cs, "IO error exception while in user mode. "
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_RUNM: /* Run mode exception */
|
||||
cpu_abort(cs, "Run mode exception while in user mode. "
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_EMUL: /* Emulation trap exception */
|
||||
cpu_abort(cs, "Emulation trap exception not handled\n");
|
||||
break;
|
||||
|
|
|
@ -81,6 +81,8 @@ blobs = files(
|
|||
'opensbi-riscv32-generic-fw_dynamic.bin',
|
||||
'opensbi-riscv64-generic-fw_dynamic.bin',
|
||||
'npcm7xx_bootrom.bin',
|
||||
'vof.bin',
|
||||
'vof-nvram.bin',
|
||||
)
|
||||
|
||||
if get_option('install_blobs')
|
||||
|
|
|
@ -422,12 +422,6 @@
|
|||
CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, e600)
|
||||
/* 32 bits "classic" PowerPC */
|
||||
/* PowerPC 6xx family */
|
||||
POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601,
|
||||
"PowerPC 601v0")
|
||||
POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601,
|
||||
"PowerPC 601v1")
|
||||
POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v,
|
||||
"PowerPC 601v2")
|
||||
POWERPC_DEF("603", CPU_POWERPC_603, 603,
|
||||
"PowerPC 603")
|
||||
POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E,
|
||||
|
@ -859,8 +853,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
|
|||
{ "mpc8555", "mpc8555_v11" },
|
||||
{ "mpc8555e", "mpc8555e_v11" },
|
||||
{ "mpc8560", "mpc8560_v21" },
|
||||
{ "601", "601_v2" },
|
||||
{ "601v", "601_v2" },
|
||||
{ "vanilla", "603" },
|
||||
{ "603e", "603e_v4.1" },
|
||||
{ "stretch", "603e_v4.1" },
|
||||
|
|
|
@ -205,9 +205,6 @@ enum {
|
|||
#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600
|
||||
#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600
|
||||
/* PowerPC 6xx cores */
|
||||
CPU_POWERPC_601_v0 = 0x00010001,
|
||||
CPU_POWERPC_601_v1 = 0x00010001,
|
||||
CPU_POWERPC_601_v2 = 0x00010002,
|
||||
CPU_POWERPC_603 = 0x00030100,
|
||||
CPU_POWERPC_603E_v11 = 0x00060101,
|
||||
CPU_POWERPC_603E_v12 = 0x00060102,
|
||||
|
|
|
@ -61,8 +61,6 @@ enum powerpc_mmu_t {
|
|||
POWERPC_MMU_BOOKE = 0x00000008,
|
||||
/* BookE 2.06 MMU model */
|
||||
POWERPC_MMU_BOOKE206 = 0x00000009,
|
||||
/* PowerPC 601 MMU model (specific BATs format) */
|
||||
POWERPC_MMU_601 = 0x0000000A,
|
||||
#define POWERPC_MMU_64 0x00010000
|
||||
/* 64 bits PowerPC MMU */
|
||||
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
|
||||
|
@ -90,20 +88,10 @@ enum powerpc_excp_t {
|
|||
POWERPC_EXCP_STD,
|
||||
/* PowerPC 40x exception model */
|
||||
POWERPC_EXCP_40x,
|
||||
/* PowerPC 601 exception model */
|
||||
POWERPC_EXCP_601,
|
||||
/* PowerPC 602 exception model */
|
||||
POWERPC_EXCP_602,
|
||||
/* PowerPC 603 exception model */
|
||||
POWERPC_EXCP_603,
|
||||
/* PowerPC G2 exception model */
|
||||
POWERPC_EXCP_G2,
|
||||
/* PowerPC 604 exception model */
|
||||
POWERPC_EXCP_604,
|
||||
/* PowerPC 7x0 exception model */
|
||||
POWERPC_EXCP_7x0,
|
||||
/* PowerPC 7x5 exception model */
|
||||
POWERPC_EXCP_7x5,
|
||||
/* PowerPC 603/604/G2 exception model */
|
||||
POWERPC_EXCP_6xx,
|
||||
/* PowerPC 7xx exception model */
|
||||
POWERPC_EXCP_7xx,
|
||||
/* PowerPC 74xx exception model */
|
||||
POWERPC_EXCP_74xx,
|
||||
/* BookE exception model */
|
||||
|
|
|
@ -89,11 +89,9 @@ enum {
|
|||
POWERPC_EXCP_VPU = 73, /* Vector unavailable exception */
|
||||
/* 40x specific exceptions */
|
||||
POWERPC_EXCP_PIT = 74, /* Programmable interval timer interrupt */
|
||||
/* 601 specific exceptions */
|
||||
POWERPC_EXCP_IO = 75, /* IO error exception */
|
||||
POWERPC_EXCP_RUNM = 76, /* Run mode exception */
|
||||
/* Vectors 75-76 are 601 specific exceptions */
|
||||
/* 602 specific exceptions */
|
||||
POWERPC_EXCP_EMUL = 77, /* Emulation trap exception */
|
||||
POWERPC_EXCP_EMUL = 77, /* Emulation trap exception */
|
||||
/* 602/603 specific exceptions */
|
||||
POWERPC_EXCP_IFTLB = 78, /* Instruction fetch TLB miss */
|
||||
POWERPC_EXCP_DLTLB = 79, /* Data load TLB miss */
|
||||
|
@ -632,8 +630,7 @@ enum {
|
|||
POWERPC_FLAG_PX = 0x00000200,
|
||||
POWERPC_FLAG_PMM = 0x00000400,
|
||||
/* Flag for special features */
|
||||
/* Decrementer clock: RTC clock (POWER, 601) or bus clock */
|
||||
POWERPC_FLAG_RTC_CLK = 0x00010000,
|
||||
/* Decrementer clock */
|
||||
POWERPC_FLAG_BUS_CLK = 0x00020000,
|
||||
/* Has CFAR */
|
||||
POWERPC_FLAG_CFAR = 0x00040000,
|
||||
|
@ -643,8 +640,6 @@ enum {
|
|||
POWERPC_FLAG_TM = 0x00100000,
|
||||
/* Has SCV (ISA 3.00) */
|
||||
POWERPC_FLAG_SCV = 0x00200000,
|
||||
/* Has HID0 for LE bit (601) */
|
||||
POWERPC_FLAG_HID0_LE = 0x00400000,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -655,7 +650,7 @@ enum {
|
|||
* the MSR are validated in hreg_compute_hflags.
|
||||
*/
|
||||
enum {
|
||||
HFLAGS_LE = 0, /* MSR_LE -- comes from elsewhere on 601 */
|
||||
HFLAGS_LE = 0, /* MSR_LE */
|
||||
HFLAGS_HV = 1, /* computed from MSR_HV and other state */
|
||||
HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */
|
||||
HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */
|
||||
|
@ -1389,11 +1384,7 @@ void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value);
|
|||
void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value);
|
||||
uint64_t cpu_ppc_load_purr(CPUPPCState *env);
|
||||
void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value);
|
||||
uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env);
|
||||
uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void cpu_ppc601_store_rtcl(CPUPPCState *env, uint32_t value);
|
||||
void cpu_ppc601_store_rtcu(CPUPPCState *env, uint32_t value);
|
||||
target_ulong load_40x_pit(CPUPPCState *env);
|
||||
void store_40x_pit(CPUPPCState *env, target_ulong val);
|
||||
void store_40x_dbcr0(CPUPPCState *env, uint32_t val);
|
||||
|
@ -1516,17 +1507,12 @@ typedef PowerPCCPU ArchCPU;
|
|||
/* SPR definitions */
|
||||
#define SPR_MQ (0x000)
|
||||
#define SPR_XER (0x001)
|
||||
#define SPR_601_VRTCU (0x004)
|
||||
#define SPR_601_VRTCL (0x005)
|
||||
#define SPR_601_UDECR (0x006)
|
||||
#define SPR_LR (0x008)
|
||||
#define SPR_CTR (0x009)
|
||||
#define SPR_UAMR (0x00D)
|
||||
#define SPR_DSCR (0x011)
|
||||
#define SPR_DSISR (0x012)
|
||||
#define SPR_DAR (0x013) /* DAE for PowerPC 601 */
|
||||
#define SPR_601_RTCU (0x014)
|
||||
#define SPR_601_RTCL (0x015)
|
||||
#define SPR_DAR (0x013)
|
||||
#define SPR_DECR (0x016)
|
||||
#define SPR_SDR1 (0x019)
|
||||
#define SPR_SRR0 (0x01A)
|
||||
|
@ -2003,7 +1989,6 @@ typedef PowerPCCPU ArchCPU;
|
|||
#define SPR_HID1 (0x3F1)
|
||||
#define SPR_IABR (0x3F2)
|
||||
#define SPR_40x_DBCR0 (0x3F2)
|
||||
#define SPR_601_HID2 (0x3F2)
|
||||
#define SPR_Exxx_L1CSR0 (0x3F2)
|
||||
#define SPR_ICTRL (0x3F3)
|
||||
#define SPR_HID2 (0x3F3)
|
||||
|
@ -2019,7 +2004,6 @@ typedef PowerPCCPU ArchCPU;
|
|||
#define DABR_MASK (~(target_ulong)0x7)
|
||||
#define SPR_Exxx_BUCSR (0x3F5)
|
||||
#define SPR_40x_IAC2 (0x3F5)
|
||||
#define SPR_601_HID5 (0x3F5)
|
||||
#define SPR_40x_DAC1 (0x3F6)
|
||||
#define SPR_MSSCR0 (0x3F6)
|
||||
#define SPR_970_HID5 (0x3F6)
|
||||
|
@ -2052,7 +2036,6 @@ typedef PowerPCCPU ArchCPU;
|
|||
#define SPR_403_PBL2 (0x3FE)
|
||||
#define SPR_PIR (0x3FF)
|
||||
#define SPR_403_PBU2 (0x3FF)
|
||||
#define SPR_601_HID15 (0x3FF)
|
||||
#define SPR_604_HID15 (0x3FF)
|
||||
#define SPR_E500_SVR (0x3FF)
|
||||
|
||||
|
@ -2117,15 +2100,6 @@ enum {
|
|||
#define PPC_RES PPC_INSNS_BASE
|
||||
/* spr/msr access instructions */
|
||||
#define PPC_MISC PPC_INSNS_BASE
|
||||
/* Deprecated instruction sets */
|
||||
/* Original POWER instruction set */
|
||||
PPC_POWER = 0x0000000000000002ULL,
|
||||
/* POWER2 instruction set extension */
|
||||
PPC_POWER2 = 0x0000000000000004ULL,
|
||||
/* Power RTC support */
|
||||
PPC_POWER_RTC = 0x0000000000000008ULL,
|
||||
/* Power-to-PowerPC bridge (601) */
|
||||
PPC_POWER_BR = 0x0000000000000010ULL,
|
||||
/* 64 bits PowerPC instruction set */
|
||||
PPC_64B = 0x0000000000000020ULL,
|
||||
/* New 64 bits extensions (PowerPC 2.0x) */
|
||||
|
@ -2236,8 +2210,7 @@ enum {
|
|||
/* popcntw and popcntd instructions */
|
||||
PPC_POPCNTWD = 0x8000000000000000ULL,
|
||||
|
||||
#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
|
||||
| PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
|
||||
#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_64B \
|
||||
| PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
|
||||
| PPC_ISEL | PPC_POPCNTB \
|
||||
| PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
|
||||
|
|
|
@ -749,83 +749,6 @@ static void register_G2_sprs(CPUPPCState *env)
|
|||
0x00000000);
|
||||
}
|
||||
|
||||
/* SPR specific to PowerPC 601 implementation */
|
||||
static void register_601_sprs(CPUPPCState *env)
|
||||
{
|
||||
/* Multiplication/division register */
|
||||
/* MQ */
|
||||
spr_register(env, SPR_MQ, "MQ",
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* RTC registers */
|
||||
spr_register(env, SPR_601_RTCU, "RTCU",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
SPR_NOACCESS, &spr_write_601_rtcu,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_601_VRTCU, "RTCU",
|
||||
&spr_read_601_rtcu, SPR_NOACCESS,
|
||||
&spr_read_601_rtcu, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_601_RTCL, "RTCL",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
SPR_NOACCESS, &spr_write_601_rtcl,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_601_VRTCL, "RTCL",
|
||||
&spr_read_601_rtcl, SPR_NOACCESS,
|
||||
&spr_read_601_rtcl, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
/* Timer */
|
||||
#if 0 /* ? */
|
||||
spr_register(env, SPR_601_UDECR, "UDECR",
|
||||
&spr_read_decr, SPR_NOACCESS,
|
||||
&spr_read_decr, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
#endif
|
||||
/* External access control */
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_EAR, "EAR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
spr_register(env, SPR_IBAT0U, "IBAT0U",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatu,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT0L, "IBAT0L",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatl,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT1U, "IBAT1U",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatu,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT1L, "IBAT1L",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatl,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT2U, "IBAT2U",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatu,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT2L, "IBAT2L",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatl,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT3U, "IBAT3U",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatu,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_IBAT3L, "IBAT3L",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_601_ubat, &spr_write_601_ubatl,
|
||||
0x00000000);
|
||||
env->nb_BATs = 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void register_74xx_sprs(CPUPPCState *env)
|
||||
{
|
||||
/* Processor identification */
|
||||
|
@ -2060,26 +1983,6 @@ static void init_excp_BookE(CPUPPCState *env)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void init_excp_601(CPUPPCState *env)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
|
||||
env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
|
||||
env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
|
||||
env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
|
||||
env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
|
||||
env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
|
||||
env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
|
||||
env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
|
||||
env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
|
||||
env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00;
|
||||
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
|
||||
env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000;
|
||||
/* Hardware reset vector */
|
||||
env->hreset_vector = 0x00000100UL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void init_excp_603(CPUPPCState *env)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
@ -2703,89 +2606,6 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data)
|
|||
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
|
||||
}
|
||||
|
||||
static void init_proc_440x4(CPUPPCState *env)
|
||||
{
|
||||
/* Time base */
|
||||
register_tbl(env);
|
||||
register_BookE_sprs(env, 0x000000000000FFFFULL);
|
||||
register_440_sprs(env);
|
||||
register_usprgh_sprs(env);
|
||||
/* Processor identification */
|
||||
spr_register(env, SPR_BOOKE_PIR, "PIR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_pir,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_IAC3, "IAC3",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_IAC4, "IAC4",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_DVC1, "DVC1",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_DVC2, "DVC2",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->nb_tlb = 64;
|
||||
env->nb_ways = 1;
|
||||
env->id_tlbs = 0;
|
||||
env->tlb_type = TLB_EMB;
|
||||
#endif
|
||||
init_excp_BookE(env);
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
/* XXX: TODO: allocate internal IRQ controller */
|
||||
|
||||
SET_FIT_PERIOD(12, 16, 20, 24);
|
||||
SET_WDT_PERIOD(20, 24, 28, 32);
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "PowerPC 440x4";
|
||||
pcc->init_proc = init_proc_440x4;
|
||||
pcc->check_pow = check_pow_nocheck;
|
||||
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
|
||||
PPC_DCR | PPC_WRTEE |
|
||||
PPC_CACHE | PPC_CACHE_ICBI |
|
||||
PPC_CACHE_DCBZ | PPC_CACHE_DCBA |
|
||||
PPC_MEM_TLBSYNC | PPC_MFTB |
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |
|
||||
PPC_440_SPEC;
|
||||
pcc->msr_mask = (1ull << MSR_POW) |
|
||||
(1ull << MSR_CE) |
|
||||
(1ull << MSR_EE) |
|
||||
(1ull << MSR_PR) |
|
||||
(1ull << MSR_FP) |
|
||||
(1ull << MSR_ME) |
|
||||
(1ull << MSR_FE0) |
|
||||
(1ull << MSR_DWE) |
|
||||
(1ull << MSR_DE) |
|
||||
(1ull << MSR_FE1) |
|
||||
(1ull << MSR_IR) |
|
||||
(1ull << MSR_DR);
|
||||
pcc->mmu_model = POWERPC_MMU_BOOKE;
|
||||
pcc->excp_model = POWERPC_EXCP_BOOKE;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_BookE;
|
||||
pcc->bfd_mach = bfd_mach_ppc_403;
|
||||
pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE |
|
||||
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
|
||||
}
|
||||
|
||||
static void init_proc_440x5(CPUPPCState *env)
|
||||
{
|
||||
/* Time base */
|
||||
|
@ -2962,7 +2782,7 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_REAL;
|
||||
pcc->excp_model = POWERPC_EXCP_603;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_RCPU;
|
||||
pcc->bfd_mach = bfd_mach_ppc_505;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -3005,7 +2825,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_MPC8xx;
|
||||
pcc->excp_model = POWERPC_EXCP_603;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_RCPU;
|
||||
pcc->bfd_mach = bfd_mach_ppc_860;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -3086,7 +2906,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_DR) |
|
||||
(1ull << MSR_RI);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_G2;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_ec603e;
|
||||
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
|
||||
|
@ -3168,7 +2988,7 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_G2;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_ec603e;
|
||||
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
|
||||
|
@ -3423,7 +3243,7 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_603;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_603;
|
||||
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
|
||||
|
@ -3892,120 +3712,6 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data)
|
|||
#endif
|
||||
|
||||
/* Non-embedded PowerPC */
|
||||
|
||||
#define POWERPC_MSRR_601 (0x0000000000001040ULL)
|
||||
|
||||
static void init_proc_601(CPUPPCState *env)
|
||||
{
|
||||
register_ne_601_sprs(env);
|
||||
register_sdr1_sprs(env);
|
||||
register_601_sprs(env);
|
||||
/* Hardware implementation registers */
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_HID0, "HID0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_hid0_601,
|
||||
0x80010080);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_HID1, "HID1",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_601_HID2, "HID2",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_601_HID5, "HID5",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
init_excp_601(env);
|
||||
/*
|
||||
* XXX: beware that dcache line size is 64
|
||||
* but dcbz uses 32 bytes "sectors"
|
||||
* XXX: this breaks clcs instruction !
|
||||
*/
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 64;
|
||||
/* Allocate hardware IRQ controller */
|
||||
ppc6xx_irq_init(env_archcpu(env));
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "PowerPC 601";
|
||||
pcc->init_proc = init_proc_601;
|
||||
pcc->check_pow = check_pow_none;
|
||||
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR |
|
||||
PPC_FLOAT |
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |
|
||||
PPC_SEGMENT | PPC_EXTERN;
|
||||
pcc->msr_mask = (1ull << MSR_EE) |
|
||||
(1ull << MSR_PR) |
|
||||
(1ull << MSR_FP) |
|
||||
(1ull << MSR_ME) |
|
||||
(1ull << MSR_FE0) |
|
||||
(1ull << MSR_SE) |
|
||||
(1ull << MSR_FE1) |
|
||||
(1ull << MSR_EP) |
|
||||
(1ull << MSR_IR) |
|
||||
(1ull << MSR_DR);
|
||||
pcc->mmu_model = POWERPC_MMU_601;
|
||||
pcc->excp_model = POWERPC_EXCP_601;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_601;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
|
||||
}
|
||||
|
||||
#define POWERPC_MSRR_601v (0x0000000000001040ULL)
|
||||
|
||||
static void init_proc_601v(CPUPPCState *env)
|
||||
{
|
||||
init_proc_601(env);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_601_HID15, "HID15",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "PowerPC 601v";
|
||||
pcc->init_proc = init_proc_601v;
|
||||
pcc->check_pow = check_pow_none;
|
||||
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR |
|
||||
PPC_FLOAT |
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |
|
||||
PPC_SEGMENT | PPC_EXTERN;
|
||||
pcc->msr_mask = (1ull << MSR_EE) |
|
||||
(1ull << MSR_PR) |
|
||||
(1ull << MSR_FP) |
|
||||
(1ull << MSR_ME) |
|
||||
(1ull << MSR_FE0) |
|
||||
(1ull << MSR_SE) |
|
||||
(1ull << MSR_FE1) |
|
||||
(1ull << MSR_EP) |
|
||||
(1ull << MSR_IR) |
|
||||
(1ull << MSR_DR);
|
||||
pcc->mmu_model = POWERPC_MMU_601;
|
||||
pcc->excp_model = POWERPC_EXCP_601;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_601;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
|
||||
}
|
||||
|
||||
static void init_proc_603(CPUPPCState *env)
|
||||
{
|
||||
register_ne_601_sprs(env);
|
||||
|
@ -4066,7 +3772,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_603;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_603;
|
||||
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
|
||||
|
@ -4105,7 +3811,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_603;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_ec603e;
|
||||
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
|
||||
|
@ -4166,7 +3872,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_604;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_604;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4247,7 +3953,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_604;
|
||||
pcc->excp_model = POWERPC_EXCP_6xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_604;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4315,7 +4021,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_7x0;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4392,7 +4098,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_7x0;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4592,7 +4298,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_7x0;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4672,7 +4378,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_7x0;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4757,7 +4463,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_7x0;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4842,7 +4548,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_32B;
|
||||
pcc->excp_model = POWERPC_EXCP_7x0;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -4918,7 +4624,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_7x5;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -5005,7 +4711,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
|
|||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
|
||||
pcc->excp_model = POWERPC_EXCP_7x5;
|
||||
pcc->excp_model = POWERPC_EXCP_7xx;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
|
||||
pcc->bfd_mach = bfd_mach_ppc_750;
|
||||
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
|
||||
|
@ -7760,7 +7466,7 @@ static void init_ppc_proc(PowerPCCPU *cpu)
|
|||
"Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((env->flags & (POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_BUS_CLK)) == 0) {
|
||||
if ((env->flags & POWERPC_FLAG_BUS_CLK) == 0) {
|
||||
fprintf(stderr, "PowerPC flags inconsistency\n"
|
||||
"Should define the time-base and decrementer clock source\n");
|
||||
exit(1);
|
||||
|
@ -8574,7 +8280,6 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|||
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
case POWERPC_MMU_SOFT_6xx:
|
||||
#if defined(TARGET_PPC64)
|
||||
case POWERPC_MMU_64B:
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1696,7 +1696,7 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
|
|||
void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
|
||||
ppc_vsr_t *xa, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
|
@ -1772,7 +1772,7 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode,
|
|||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
|
||||
ppc_vsr_t *xa, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
|
@ -1843,7 +1843,7 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode,
|
|||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
|
||||
ppc_vsr_t *xa, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
|
@ -1919,7 +1919,7 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode,
|
|||
#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
|
@ -1959,7 +1959,7 @@ VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0)
|
|||
#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
|
@ -2004,7 +2004,7 @@ VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0)
|
|||
#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
|
@ -2472,7 +2472,7 @@ void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
|
|||
void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
|
||||
ppc_vsr_t *xa, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
|
@ -2498,7 +2498,7 @@ VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
|
|||
void helper_##name(CPUPPCState *env, \
|
||||
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
bool vxsnan_flag = false, vex_flag = false; \
|
||||
\
|
||||
if (unlikely(float64_is_any_nan(xa->VsrD(0)) || \
|
||||
|
@ -2533,7 +2533,7 @@ VSX_MAX_MINC(xsmincdp, 0);
|
|||
void helper_##name(CPUPPCState *env, \
|
||||
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
bool vxsnan_flag = false, vex_flag = false; \
|
||||
\
|
||||
if (unlikely(float64_is_any_nan(xa->VsrD(0)))) { \
|
||||
|
@ -2654,7 +2654,7 @@ VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0)
|
|||
#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
|
@ -2833,7 +2833,7 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb)
|
|||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
int all_flags = env->fp_status.float_exception_flags, flags; \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
|
@ -2917,7 +2917,7 @@ VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL)
|
|||
#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
|
@ -2990,7 +2990,7 @@ VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128)
|
|||
#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
FloatRoundMode curr_rounding_mode; \
|
||||
\
|
||||
|
|
|
@ -7,7 +7,6 @@ DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32)
|
|||
#if !defined(CONFIG_USER_ONLY)
|
||||
DEF_HELPER_2(store_msr, void, env, tl)
|
||||
DEF_HELPER_1(rfi, void, env)
|
||||
DEF_HELPER_1(rfsvc, void, env)
|
||||
DEF_HELPER_1(40x_rfci, void, env)
|
||||
DEF_HELPER_1(rfci, void, env)
|
||||
DEF_HELPER_1(rfdi, void, env)
|
||||
|
@ -653,14 +652,9 @@ DEF_HELPER_2(book3s_msgclr, void, env, tl)
|
|||
#endif
|
||||
|
||||
DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
|
||||
DEF_HELPER_FLAGS_2(clcs, TCG_CALL_NO_RWG_SE, tl, env, i32)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
DEF_HELPER_2(rac, tl, env, tl)
|
||||
#endif
|
||||
DEF_HELPER_3(div, tl, env, tl, tl)
|
||||
DEF_HELPER_3(divo, tl, env, tl, tl)
|
||||
DEF_HELPER_3(divs, tl, env, tl, tl)
|
||||
DEF_HELPER_3(divso, tl, env, tl, tl)
|
||||
|
||||
DEF_HELPER_2(load_dcr, tl, env, tl)
|
||||
DEF_HELPER_3(store_dcr, void, env, tl, tl)
|
||||
|
@ -674,8 +668,6 @@ DEF_HELPER_FLAGS_1(load_tbu, TCG_CALL_NO_RWG, tl, env)
|
|||
DEF_HELPER_FLAGS_1(load_atbl, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_1(load_atbu, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_1(load_vtb, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_1(load_601_rtcl, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_1(load_601_rtcu, TCG_CALL_NO_RWG, tl, env)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#if defined(TARGET_PPC64)
|
||||
DEF_HELPER_FLAGS_1(load_purr, TCG_CALL_NO_RWG, tl, env)
|
||||
|
@ -693,15 +685,12 @@ DEF_HELPER_FLAGS_2(store_tbl, TCG_CALL_NO_RWG, void, env, tl)
|
|||
DEF_HELPER_FLAGS_2(store_tbu, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_atbl, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_atbu, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_601_rtcl, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_601_rtcu, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_1(load_decr, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_2(store_decr, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_1(load_hdecr, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_2(store_hdecr, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_vtb, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_tbu40, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_2(store_hid0_601, void, env, tl)
|
||||
DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
||||
|
@ -715,8 +704,6 @@ DEF_HELPER_3(store_ibatl, void, env, i32, tl)
|
|||
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
|
||||
DEF_HELPER_3(store_dbatl, void, env, i32, tl)
|
||||
DEF_HELPER_3(store_dbatu, void, env, i32, tl)
|
||||
DEF_HELPER_3(store_601_batl, void, env, i32, tl)
|
||||
DEF_HELPER_3(store_601_batu, void, env, i32, tl)
|
||||
#endif
|
||||
|
||||
#define dh_alias_fprp ptr
|
||||
|
|
|
@ -59,15 +59,6 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
|
|||
msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) |
|
||||
(1 << MSR_DR) | (1 << MSR_FP));
|
||||
|
||||
if (ppc_flags & POWERPC_FLAG_HID0_LE) {
|
||||
/*
|
||||
* Note that MSR_LE is not set in env->msr_mask for this cpu,
|
||||
* and so will never be set in msr.
|
||||
*/
|
||||
uint32_t le = extract32(env->spr[SPR_HID0], 3, 1);
|
||||
hflags |= le << MSR_LE;
|
||||
}
|
||||
|
||||
if (ppc_flags & POWERPC_FLAG_DE) {
|
||||
target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0];
|
||||
if (dbcr0 & DBCR0_ICMP) {
|
||||
|
@ -249,7 +240,6 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
|
|||
hreg_swap_gpr_tgpr(env);
|
||||
}
|
||||
if (unlikely((value >> MSR_EP) & 1) != msr_ep) {
|
||||
/* Change the exception prefix on PowerPC 601 */
|
||||
env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000;
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -422,72 +422,6 @@ uint64_t helper_PEXTD(uint64_t src, uint64_t mask)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PowerPC 601 specific instructions (POWER bridge) */
|
||||
target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
|
||||
{
|
||||
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
|
||||
|
||||
if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
|
||||
(int32_t)arg2 == 0) {
|
||||
env->spr[SPR_MQ] = 0;
|
||||
return INT32_MIN;
|
||||
} else {
|
||||
env->spr[SPR_MQ] = tmp % arg2;
|
||||
return tmp / (int32_t)arg2;
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
|
||||
target_ulong arg2)
|
||||
{
|
||||
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
|
||||
|
||||
if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
|
||||
(int32_t)arg2 == 0) {
|
||||
env->so = env->ov = 1;
|
||||
env->spr[SPR_MQ] = 0;
|
||||
return INT32_MIN;
|
||||
} else {
|
||||
env->spr[SPR_MQ] = tmp % arg2;
|
||||
tmp /= (int32_t)arg2;
|
||||
if ((int32_t)tmp != tmp) {
|
||||
env->so = env->ov = 1;
|
||||
} else {
|
||||
env->ov = 0;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
|
||||
target_ulong arg2)
|
||||
{
|
||||
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
|
||||
(int32_t)arg2 == 0) {
|
||||
env->spr[SPR_MQ] = 0;
|
||||
return INT32_MIN;
|
||||
} else {
|
||||
env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
|
||||
return (int32_t)arg1 / (int32_t)arg2;
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
|
||||
target_ulong arg2)
|
||||
{
|
||||
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
|
||||
(int32_t)arg2 == 0) {
|
||||
env->so = env->ov = 1;
|
||||
env->spr[SPR_MQ] = 0;
|
||||
return INT32_MIN;
|
||||
} else {
|
||||
env->ov = 0;
|
||||
env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
|
||||
return (int32_t)arg1 / (int32_t)arg2;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Altivec extension helpers */
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
|
|
|
@ -205,9 +205,8 @@ static int cpu_pre_save(void *opaque)
|
|||
}
|
||||
}
|
||||
|
||||
/* Retain migration compatibility for pre 6.0 for 601 machines. */
|
||||
env->hflags_compat_nmsr = (env->flags & POWERPC_FLAG_HID0_LE
|
||||
? env->hflags & MSR_LE : 0);
|
||||
/* Used to retain migration compatibility for pre 6.0 for 601 machines. */
|
||||
env->hflags_compat_nmsr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -211,21 +211,6 @@ void helper_store_lpidr(CPUPPCState *env, target_ulong val)
|
|||
tlb_flush(env_cpu(env));
|
||||
}
|
||||
|
||||
void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
target_ulong hid0;
|
||||
|
||||
hid0 = env->spr[SPR_HID0];
|
||||
env->spr[SPR_HID0] = (uint32_t)val;
|
||||
|
||||
if ((val ^ hid0) & 0x00000008) {
|
||||
/* Change current endianness */
|
||||
hreg_compute_hflags(env);
|
||||
qemu_log("%s: set endianness to %c => %08x\n", __func__,
|
||||
val & 0x8 ? 'l' : 'b', env->hflags);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
/* Bits 26 & 27 affect single-stepping. */
|
||||
|
@ -239,31 +224,6 @@ void helper_store_40x_sler(CPUPPCState *env, target_ulong val)
|
|||
store_40x_sler(env, val);
|
||||
}
|
||||
#endif
|
||||
/*****************************************************************************/
|
||||
/* PowerPC 601 specific instructions (POWER bridge) */
|
||||
|
||||
target_ulong helper_clcs(CPUPPCState *env, uint32_t arg)
|
||||
{
|
||||
switch (arg) {
|
||||
case 0x0CUL:
|
||||
/* Instruction cache line size */
|
||||
return env->icache_line_size;
|
||||
case 0x0DUL:
|
||||
/* Data cache line size */
|
||||
return env->dcache_line_size;
|
||||
case 0x0EUL:
|
||||
/* Minimum cache line size */
|
||||
return (env->icache_line_size < env->dcache_line_size) ?
|
||||
env->icache_line_size : env->dcache_line_size;
|
||||
case 0x0FUL:
|
||||
/* Maximum cache line size */
|
||||
return (env->icache_line_size > env->dcache_line_size) ?
|
||||
env->icache_line_size : env->dcache_line_size;
|
||||
default:
|
||||
/* Undefined */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Special registers manipulation */
|
||||
|
|
|
@ -125,30 +125,6 @@ static int hash32_bat_prot(PowerPCCPU *cpu,
|
|||
return prot;
|
||||
}
|
||||
|
||||
static target_ulong hash32_bat_601_size(PowerPCCPU *cpu,
|
||||
target_ulong batu, target_ulong batl)
|
||||
{
|
||||
if (!(batl & BATL32_601_V)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
|
||||
}
|
||||
|
||||
static int hash32_bat_601_prot(int mmu_idx,
|
||||
target_ulong batu, target_ulong batl)
|
||||
{
|
||||
int key, pp;
|
||||
|
||||
pp = batu & BATU32_601_PP;
|
||||
if (mmuidx_pr(mmu_idx) == 0) {
|
||||
key = !!(batu & BATU32_601_KS);
|
||||
} else {
|
||||
key = !!(batu & BATU32_601_KP);
|
||||
}
|
||||
return ppc_hash32_pp_prot(key, pp, 0);
|
||||
}
|
||||
|
||||
static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
|
||||
MMUAccessType access_type, int *prot,
|
||||
int mmu_idx)
|
||||
|
@ -172,11 +148,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
|
|||
target_ulong batl = BATlt[i];
|
||||
target_ulong mask;
|
||||
|
||||
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
|
||||
mask = hash32_bat_601_size(cpu, batu, batl);
|
||||
} else {
|
||||
mask = hash32_bat_size(mmu_idx, batu, batl);
|
||||
}
|
||||
mask = hash32_bat_size(mmu_idx, batu, batl);
|
||||
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
|
||||
" BATl " TARGET_FMT_lx "\n", __func__,
|
||||
ifetch ? 'I' : 'D', i, ea, batu, batl);
|
||||
|
@ -184,11 +156,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
|
|||
if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
|
||||
hwaddr raddr = (batl & mask) | (ea & ~mask);
|
||||
|
||||
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
|
||||
*prot = hash32_bat_601_prot(mmu_idx, batu, batl);
|
||||
} else {
|
||||
*prot = hash32_bat_prot(cpu, batu, batl);
|
||||
}
|
||||
*prot = hash32_bat_prot(cpu, batu, batl);
|
||||
|
||||
return raddr & TARGET_PAGE_MASK;
|
||||
}
|
||||
|
@ -231,18 +199,6 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
|
|||
|
||||
qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
|
||||
|
||||
if ((sr & 0x1FF00000) >> 20 == 0x07f) {
|
||||
/*
|
||||
* Memory-forced I/O controller interface access
|
||||
*
|
||||
* If T=1 and BUID=x'07F', the 601 performs a memory access
|
||||
* to SR[28-31] LA[4-31], bypassing all protection mechanisms.
|
||||
*/
|
||||
*raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
|
||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
/* No code fetch is allowed in direct-store areas */
|
||||
if (guest_visible) {
|
||||
|
|
|
@ -34,15 +34,6 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
|
|||
#define BATL32_WIMG 0x00000078
|
||||
#define BATL32_PP 0x00000003
|
||||
|
||||
/* PowerPC 601 has slightly different BAT registers */
|
||||
|
||||
#define BATU32_601_KS 0x00000008
|
||||
#define BATU32_601_KP 0x00000004
|
||||
#define BATU32_601_PP 0x00000003
|
||||
|
||||
#define BATL32_601_V 0x00000040
|
||||
#define BATL32_601_BL 0x0000003f
|
||||
|
||||
/*
|
||||
* Hash page table definitions
|
||||
*/
|
||||
|
|
|
@ -327,13 +327,9 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
|
|||
uint64_t pte;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
|
||||
" mmu_idx %u (prot %c%c%c) 0x%"HWADDR_PRIx"\n",
|
||||
" mmu_idx %u 0x%"HWADDR_PRIx"\n",
|
||||
__func__, access_str(access_type),
|
||||
eaddr, mmu_idx,
|
||||
*h_prot & PAGE_READ ? 'r' : '-',
|
||||
*h_prot & PAGE_WRITE ? 'w' : '-',
|
||||
*h_prot & PAGE_EXEC ? 'x' : '-',
|
||||
g_raddr);
|
||||
eaddr, mmu_idx, g_raddr);
|
||||
|
||||
*h_page_size = PRTBE_R_GET_RTS(pate.dw0);
|
||||
/* No valid pte or access denied due to protection */
|
||||
|
|
|
@ -441,29 +441,9 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
|
|||
ret = -3;
|
||||
}
|
||||
} else {
|
||||
target_ulong sr;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
|
||||
/* Direct-store segment : absolutely *BUGGY* for now */
|
||||
|
||||
/*
|
||||
* Direct-store implies a 32-bit MMU.
|
||||
* Check the Segment Register's bus unit ID (BUID).
|
||||
*/
|
||||
sr = env->sr[eaddr >> 28];
|
||||
if ((sr & 0x1FF00000) >> 20 == 0x07f) {
|
||||
/*
|
||||
* Memory-forced I/O controller interface access
|
||||
*
|
||||
* If T=1 and BUID=x'07F', the 601 performs a memory
|
||||
* access to SR[28-31] LA[4-31], bypassing all protection
|
||||
* mechanisms.
|
||||
*/
|
||||
ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ACCESS_INT:
|
||||
/* Integer load/store : only access allowed */
|
||||
|
@ -1539,7 +1519,6 @@ bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
|
|||
#endif
|
||||
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
return ppc_hash32_xlate(cpu, eaddr, access_type, raddrp,
|
||||
psizep, protp, mmu_idx, guest_visible);
|
||||
|
||||
|
|
|
@ -279,88 +279,6 @@ void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
|
|||
env->DBAT[1][nr] = value;
|
||||
}
|
||||
|
||||
void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
|
||||
{
|
||||
target_ulong mask;
|
||||
#if defined(FLUSH_ALL_TLBS)
|
||||
int do_inval;
|
||||
#endif
|
||||
|
||||
dump_store_bat(env, 'I', 0, nr, value);
|
||||
if (env->IBAT[0][nr] != value) {
|
||||
#if defined(FLUSH_ALL_TLBS)
|
||||
do_inval = 0;
|
||||
#endif
|
||||
mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
|
||||
if (env->IBAT[1][nr] & 0x40) {
|
||||
/* Invalidate BAT only if it is valid */
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
|
||||
#else
|
||||
do_inval = 1;
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* When storing valid upper BAT, mask BEPI and BRPN and
|
||||
* invalidate all TLBs covered by this BAT
|
||||
*/
|
||||
env->IBAT[0][nr] = (value & 0x00001FFFUL) |
|
||||
(value & ~0x0001FFFFUL & ~mask);
|
||||
env->DBAT[0][nr] = env->IBAT[0][nr];
|
||||
if (env->IBAT[1][nr] & 0x40) {
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
|
||||
#else
|
||||
do_inval = 1;
|
||||
#endif
|
||||
}
|
||||
#if defined(FLUSH_ALL_TLBS)
|
||||
if (do_inval) {
|
||||
tlb_flush(env_cpu(env));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
|
||||
{
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
target_ulong mask;
|
||||
#else
|
||||
int do_inval;
|
||||
#endif
|
||||
|
||||
dump_store_bat(env, 'I', 1, nr, value);
|
||||
if (env->IBAT[1][nr] != value) {
|
||||
#if defined(FLUSH_ALL_TLBS)
|
||||
do_inval = 0;
|
||||
#endif
|
||||
if (env->IBAT[1][nr] & 0x40) {
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
|
||||
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
|
||||
#else
|
||||
do_inval = 1;
|
||||
#endif
|
||||
}
|
||||
if (value & 0x40) {
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
mask = (value << 17) & 0x0FFE0000UL;
|
||||
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
|
||||
#else
|
||||
do_inval = 1;
|
||||
#endif
|
||||
}
|
||||
env->IBAT[1][nr] = value;
|
||||
env->DBAT[1][nr] = value;
|
||||
#if defined(FLUSH_ALL_TLBS)
|
||||
if (do_inval) {
|
||||
tlb_flush(env_cpu(env));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* TLB management */
|
||||
void ppc_tlb_invalidate_all(CPUPPCState *env)
|
||||
|
@ -392,7 +310,6 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
|
|||
booke206_flush_tlb(env, -1, 0);
|
||||
break;
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
env->tlb_need_flush = 0;
|
||||
tlb_flush(env_cpu(env));
|
||||
break;
|
||||
|
@ -426,7 +343,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
|
|||
}
|
||||
break;
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
/*
|
||||
* Actual CPUs invalidate entire congruence classes based on
|
||||
* the geometry of their TLBs and some OSes take that into
|
||||
|
|
|
@ -45,8 +45,6 @@ void spr_read_tbl(DisasContext *ctx, int gprn, int sprn);
|
|||
void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_atbu(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn);
|
||||
|
@ -77,12 +75,6 @@ void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn);
|
|||
void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn);
|
||||
|
|
|
@ -63,16 +63,6 @@ void helper_store_purr(CPUPPCState *env, target_ulong val)
|
|||
}
|
||||
#endif
|
||||
|
||||
target_ulong helper_load_601_rtcl(CPUPPCState *env)
|
||||
{
|
||||
return cpu_ppc601_load_rtcl(env);
|
||||
}
|
||||
|
||||
target_ulong helper_load_601_rtcu(CPUPPCState *env)
|
||||
{
|
||||
return cpu_ppc601_load_rtcu(env);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void helper_store_tbl(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
|
@ -94,16 +84,6 @@ void helper_store_atbu(CPUPPCState *env, target_ulong val)
|
|||
cpu_ppc_store_atbu(env, val);
|
||||
}
|
||||
|
||||
void helper_store_601_rtcl(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
cpu_ppc601_store_rtcl(env, val);
|
||||
}
|
||||
|
||||
void helper_store_601_rtcu(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
cpu_ppc601_store_rtcu(env, val);
|
||||
}
|
||||
|
||||
target_ulong helper_load_decr(CPUPPCState *env)
|
||||
{
|
||||
return cpu_ppc_load_decr(env);
|
||||
|
|
|
@ -794,61 +794,6 @@ void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* PowerPC 601 specific registers */
|
||||
/* RTC */
|
||||
void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env);
|
||||
}
|
||||
|
||||
void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]);
|
||||
}
|
||||
|
||||
void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]);
|
||||
}
|
||||
|
||||
void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
|
||||
/* Must stop the translation as endianness may have changed */
|
||||
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Unified bats */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
|
||||
offsetof(CPUPPCState,
|
||||
IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
|
||||
}
|
||||
|
||||
void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
|
||||
gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
|
||||
gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PowerPC 40x specific registers */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn)
|
||||
|
@ -5609,669 +5554,6 @@ static void gen_ecowx(DisasContext *ctx)
|
|||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
/* PowerPC 601 specific instructions */
|
||||
|
||||
/* abs - abs. */
|
||||
static void gen_abs(DisasContext *ctx)
|
||||
{
|
||||
TCGv d = cpu_gpr[rD(ctx->opcode)];
|
||||
TCGv a = cpu_gpr[rA(ctx->opcode)];
|
||||
|
||||
tcg_gen_abs_tl(d, a);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, d);
|
||||
}
|
||||
}
|
||||
|
||||
/* abso - abso. */
|
||||
static void gen_abso(DisasContext *ctx)
|
||||
{
|
||||
TCGv d = cpu_gpr[rD(ctx->opcode)];
|
||||
TCGv a = cpu_gpr[rA(ctx->opcode)];
|
||||
|
||||
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_ov, a, 0x80000000);
|
||||
tcg_gen_abs_tl(d, a);
|
||||
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, d);
|
||||
}
|
||||
}
|
||||
|
||||
/* clcs */
|
||||
static void gen_clcs(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
|
||||
gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
/* Rc=1 sets CR0 to an undefined state */
|
||||
}
|
||||
|
||||
/* div - div. */
|
||||
static void gen_div(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
|
||||
cpu_gpr[rB(ctx->opcode)]);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* divo - divo. */
|
||||
static void gen_divo(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
|
||||
cpu_gpr[rB(ctx->opcode)]);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* divs - divs. */
|
||||
static void gen_divs(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
|
||||
cpu_gpr[rB(ctx->opcode)]);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* divso - divso. */
|
||||
static void gen_divso(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_env,
|
||||
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* doz - doz. */
|
||||
static void gen_doz(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)],
|
||||
cpu_gpr[rA(ctx->opcode)], l1);
|
||||
tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
|
||||
cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_br(l2);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
|
||||
gen_set_label(l2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* dozo - dozo. */
|
||||
static void gen_dozo(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
/* Start with XER OV disabled, the most likely case */
|
||||
tcg_gen_movi_tl(cpu_ov, 0);
|
||||
tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)],
|
||||
cpu_gpr[rA(ctx->opcode)], l1);
|
||||
tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0);
|
||||
tcg_gen_andc_tl(t1, t1, t2);
|
||||
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
|
||||
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
|
||||
tcg_gen_movi_tl(cpu_ov, 1);
|
||||
tcg_gen_movi_tl(cpu_so, 1);
|
||||
tcg_gen_br(l2);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
|
||||
gen_set_label(l2);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* dozi */
|
||||
static void gen_dozi(DisasContext *ctx)
|
||||
{
|
||||
target_long simm = SIMM(ctx->opcode);
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1);
|
||||
tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_br(l2);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
|
||||
gen_set_label(l2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* lscbx - lscbx. */
|
||||
static void gen_lscbx(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv_i32 t1 = tcg_const_i32(rD(ctx->opcode));
|
||||
TCGv_i32 t2 = tcg_const_i32(rA(ctx->opcode));
|
||||
TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
|
||||
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t2);
|
||||
tcg_temp_free_i32(t3);
|
||||
tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
|
||||
tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, t0);
|
||||
}
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
/* maskg - maskg. */
|
||||
static void gen_maskg(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
TCGv t3 = tcg_temp_new();
|
||||
tcg_gen_movi_tl(t3, 0xFFFFFFFF);
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F);
|
||||
tcg_gen_addi_tl(t2, t0, 1);
|
||||
tcg_gen_shr_tl(t2, t3, t2);
|
||||
tcg_gen_shr_tl(t3, t3, t1);
|
||||
tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3);
|
||||
tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
|
||||
tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
||||
gen_set_label(l1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
tcg_temp_free(t3);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* maskir - maskir. */
|
||||
static void gen_maskir(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
|
||||
tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* mul - mul. */
|
||||
static void gen_mul(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
|
||||
tcg_gen_mul_i64(t0, t0, t1);
|
||||
tcg_gen_trunc_i64_tl(t2, t0);
|
||||
gen_store_spr(SPR_MQ, t2);
|
||||
tcg_gen_shri_i64(t1, t0, 32);
|
||||
tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* mulo - mulo. */
|
||||
static void gen_mulo(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
/* Start with XER OV disabled, the most likely case */
|
||||
tcg_gen_movi_tl(cpu_ov, 0);
|
||||
tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
|
||||
tcg_gen_mul_i64(t0, t0, t1);
|
||||
tcg_gen_trunc_i64_tl(t2, t0);
|
||||
gen_store_spr(SPR_MQ, t2);
|
||||
tcg_gen_shri_i64(t1, t0, 32);
|
||||
tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
|
||||
tcg_gen_ext32s_i64(t1, t0);
|
||||
tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
|
||||
tcg_gen_movi_tl(cpu_ov, 1);
|
||||
tcg_gen_movi_tl(cpu_so, 1);
|
||||
gen_set_label(l1);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* nabs - nabs. */
|
||||
static void gen_nabs(DisasContext *ctx)
|
||||
{
|
||||
TCGv d = cpu_gpr[rD(ctx->opcode)];
|
||||
TCGv a = cpu_gpr[rA(ctx->opcode)];
|
||||
|
||||
tcg_gen_abs_tl(d, a);
|
||||
tcg_gen_neg_tl(d, d);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, d);
|
||||
}
|
||||
}
|
||||
|
||||
/* nabso - nabso. */
|
||||
static void gen_nabso(DisasContext *ctx)
|
||||
{
|
||||
TCGv d = cpu_gpr[rD(ctx->opcode)];
|
||||
TCGv a = cpu_gpr[rA(ctx->opcode)];
|
||||
|
||||
tcg_gen_abs_tl(d, a);
|
||||
tcg_gen_neg_tl(d, d);
|
||||
/* nabs never overflows */
|
||||
tcg_gen_movi_tl(cpu_ov, 0);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, d);
|
||||
}
|
||||
}
|
||||
|
||||
/* rlmi - rlmi. */
|
||||
static void gen_rlmi(DisasContext *ctx)
|
||||
{
|
||||
uint32_t mb = MB(ctx->opcode);
|
||||
uint32_t me = ME(ctx->opcode);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
|
||||
tcg_gen_andi_tl(t0, t0, MASK(mb, me));
|
||||
tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
|
||||
~MASK(mb, me));
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], t0);
|
||||
tcg_temp_free(t0);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* rrib - rrib. */
|
||||
static void gen_rrib(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_movi_tl(t1, 0x80000000);
|
||||
tcg_gen_shr_tl(t1, t1, t0);
|
||||
tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
|
||||
tcg_gen_and_tl(t0, t0, t1);
|
||||
tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], t1);
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sle - sle. */
|
||||
static void gen_sle(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_subfi_tl(t1, 32, t1);
|
||||
tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_or_tl(t1, t0, t1);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
|
||||
gen_store_spr(SPR_MQ, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sleq - sleq. */
|
||||
static void gen_sleq(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_movi_tl(t2, 0xFFFFFFFF);
|
||||
tcg_gen_shl_tl(t2, t2, t0);
|
||||
tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
|
||||
gen_load_spr(t1, SPR_MQ);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_and_tl(t0, t0, t2);
|
||||
tcg_gen_andc_tl(t1, t1, t2);
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sliq - sliq. */
|
||||
static void gen_sliq(DisasContext *ctx)
|
||||
{
|
||||
int sh = SH(ctx->opcode);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_shli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
|
||||
tcg_gen_shri_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
|
||||
tcg_gen_or_tl(t1, t0, t1);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
|
||||
gen_store_spr(SPR_MQ, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* slliq - slliq. */
|
||||
static void gen_slliq(DisasContext *ctx)
|
||||
{
|
||||
int sh = SH(ctx->opcode);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
|
||||
gen_load_spr(t1, SPR_MQ);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_andi_tl(t0, t0, (0xFFFFFFFFU << sh));
|
||||
tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU << sh));
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sllq - sllq. */
|
||||
static void gen_sllq(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_local_new();
|
||||
TCGv t1 = tcg_temp_local_new();
|
||||
TCGv t2 = tcg_temp_local_new();
|
||||
tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_movi_tl(t1, 0xFFFFFFFF);
|
||||
tcg_gen_shl_tl(t1, t1, t2);
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
|
||||
gen_load_spr(t0, SPR_MQ);
|
||||
tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
tcg_gen_br(l2);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
|
||||
gen_load_spr(t2, SPR_MQ);
|
||||
tcg_gen_andc_tl(t1, t2, t1);
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
gen_set_label(l2);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* slq - slq. */
|
||||
static void gen_slq(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_subfi_tl(t1, 32, t1);
|
||||
tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_or_tl(t1, t0, t1);
|
||||
gen_store_spr(SPR_MQ, t1);
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
|
||||
tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
|
||||
gen_set_label(l1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sraiq - sraiq. */
|
||||
static void gen_sraiq(DisasContext *ctx)
|
||||
{
|
||||
int sh = SH(ctx->opcode);
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
|
||||
tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_movi_tl(cpu_ca, 0);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
|
||||
tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
|
||||
tcg_gen_movi_tl(cpu_ca, 1);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sraq - sraq. */
|
||||
static void gen_sraq(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_local_new();
|
||||
TCGv t2 = tcg_temp_local_new();
|
||||
tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
|
||||
tcg_gen_sar_tl(t1, cpu_gpr[rS(ctx->opcode)], t2);
|
||||
tcg_gen_subfi_tl(t2, 32, t2);
|
||||
tcg_gen_shl_tl(t2, cpu_gpr[rS(ctx->opcode)], t2);
|
||||
tcg_gen_or_tl(t0, t0, t2);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l1);
|
||||
tcg_gen_mov_tl(t2, cpu_gpr[rS(ctx->opcode)]);
|
||||
tcg_gen_sari_tl(t1, cpu_gpr[rS(ctx->opcode)], 31);
|
||||
gen_set_label(l1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1);
|
||||
tcg_gen_movi_tl(cpu_ca, 0);
|
||||
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2);
|
||||
tcg_gen_movi_tl(cpu_ca, 1);
|
||||
gen_set_label(l2);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sre - sre. */
|
||||
static void gen_sre(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_subfi_tl(t1, 32, t1);
|
||||
tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_or_tl(t1, t0, t1);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
|
||||
gen_store_spr(SPR_MQ, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* srea - srea. */
|
||||
static void gen_srea(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_sar_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sreq */
|
||||
static void gen_sreq(DisasContext *ctx)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
TCGv t2 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_movi_tl(t1, 0xFFFFFFFF);
|
||||
tcg_gen_shr_tl(t1, t1, t0);
|
||||
tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
|
||||
gen_load_spr(t2, SPR_MQ);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_and_tl(t0, t0, t1);
|
||||
tcg_gen_andc_tl(t2, t2, t1);
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* sriq */
|
||||
static void gen_sriq(DisasContext *ctx)
|
||||
{
|
||||
int sh = SH(ctx->opcode);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
|
||||
tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
|
||||
tcg_gen_or_tl(t1, t0, t1);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
|
||||
gen_store_spr(SPR_MQ, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* srliq */
|
||||
static void gen_srliq(DisasContext *ctx)
|
||||
{
|
||||
int sh = SH(ctx->opcode);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_rotri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
|
||||
gen_load_spr(t1, SPR_MQ);
|
||||
gen_store_spr(SPR_MQ, t0);
|
||||
tcg_gen_andi_tl(t0, t0, (0xFFFFFFFFU >> sh));
|
||||
tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU >> sh));
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* srlq */
|
||||
static void gen_srlq(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_local_new();
|
||||
TCGv t1 = tcg_temp_local_new();
|
||||
TCGv t2 = tcg_temp_local_new();
|
||||
tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_movi_tl(t1, 0xFFFFFFFF);
|
||||
tcg_gen_shr_tl(t2, t1, t2);
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
|
||||
gen_load_spr(t0, SPR_MQ);
|
||||
tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
|
||||
tcg_gen_br(l2);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
|
||||
tcg_gen_and_tl(t0, t0, t2);
|
||||
gen_load_spr(t1, SPR_MQ);
|
||||
tcg_gen_andc_tl(t1, t1, t2);
|
||||
tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
|
||||
gen_set_label(l2);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free(t2);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* srq */
|
||||
static void gen_srq(DisasContext *ctx)
|
||||
{
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
|
||||
tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_subfi_tl(t1, 32, t1);
|
||||
tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
|
||||
tcg_gen_or_tl(t1, t0, t1);
|
||||
gen_store_spr(SPR_MQ, t1);
|
||||
tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
|
||||
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
|
||||
tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
|
||||
gen_set_label(l1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
}
|
||||
|
||||
/* 602 - 603 - G2 TLB management */
|
||||
|
||||
/* tlbld */
|
||||
|
@ -6296,81 +5578,6 @@ static void gen_tlbli_6xx(DisasContext *ctx)
|
|||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
|
||||
/* POWER instructions not in PowerPC 601 */
|
||||
|
||||
/* clf */
|
||||
static void gen_clf(DisasContext *ctx)
|
||||
{
|
||||
/* Cache line flush: implemented as no-op */
|
||||
}
|
||||
|
||||
/* cli */
|
||||
static void gen_cli(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_PRIV;
|
||||
#else
|
||||
/* Cache line invalidate: privileged and treated as no-op */
|
||||
CHK_SV;
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
|
||||
/* dclst */
|
||||
static void gen_dclst(DisasContext *ctx)
|
||||
{
|
||||
/* Data cache line store: treated as no-op */
|
||||
}
|
||||
|
||||
static void gen_mfsri(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_PRIV;
|
||||
#else
|
||||
int ra = rA(ctx->opcode);
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0;
|
||||
|
||||
CHK_SV;
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
tcg_gen_extract_tl(t0, t0, 28, 4);
|
||||
gen_helper_load_sr(cpu_gpr[rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
if (ra != 0 && ra != rd) {
|
||||
tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
|
||||
}
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
|
||||
static void gen_rac(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_PRIV;
|
||||
#else
|
||||
TCGv t0;
|
||||
|
||||
CHK_SV;
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
gen_helper_rac(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
|
||||
static void gen_rfsvc(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_PRIV;
|
||||
#else
|
||||
CHK_SV;
|
||||
|
||||
gen_helper_rfsvc(cpu_env);
|
||||
ctx->base.is_jmp = DISAS_EXIT;
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
|
||||
/* svc is not implemented for now */
|
||||
|
||||
/* BookE specific instructions */
|
||||
|
||||
/* XXX: not implemented on 440 ? */
|
||||
|
@ -7718,56 +6925,8 @@ GEN_HANDLER_E(slbsync, 0x1F, 0x12, 0x0A, 0x03FFF801, PPC_NONE, PPC2_ISA300),
|
|||
#endif
|
||||
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN),
|
||||
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN),
|
||||
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR),
|
||||
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR),
|
||||
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR),
|
||||
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
|
||||
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB),
|
||||
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
|
||||
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),
|
||||
GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER),
|
||||
GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER),
|
||||
GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER),
|
||||
GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER),
|
||||
GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER),
|
||||
GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
|
||||
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
|
||||
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2),
|
||||
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2),
|
||||
GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
|
||||
GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
|
||||
GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2),
|
||||
GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2),
|
||||
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI),
|
||||
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA),
|
||||
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR),
|
||||
|
@ -8463,7 +7622,6 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|||
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
|
||||
#endif
|
||||
ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B
|
||||
|| env->mmu_model == POWERPC_MMU_601
|
||||
|| env->mmu_model & POWERPC_MMU_64;
|
||||
|
||||
ctx->fpu_enabled = (hflags >> HFLAGS_FP) & 1;
|
||||
|
|
|
@ -1105,185 +1105,6 @@ static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
|
|||
/* stfiwx */
|
||||
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
|
||||
|
||||
/* POWER2 specific instructions */
|
||||
/* Quad manipulation (load/store two floats at a time) */
|
||||
|
||||
/* lfq */
|
||||
static void gen_lfq(DisasContext *ctx)
|
||||
{
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0;
|
||||
TCGv_i64 t1;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_addr_imm_index(ctx, t0, 0);
|
||||
gen_qemu_ld64_i64(ctx, t1, t0);
|
||||
set_fpr(rd, t1);
|
||||
gen_addr_add(ctx, t0, t0, 8);
|
||||
gen_qemu_ld64_i64(ctx, t1, t0);
|
||||
set_fpr((rd + 1) % 32, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
|
||||
/* lfqu */
|
||||
static void gen_lfqu(DisasContext *ctx)
|
||||
{
|
||||
int ra = rA(ctx->opcode);
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0, t1;
|
||||
TCGv_i64 t2;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new();
|
||||
t2 = tcg_temp_new_i64();
|
||||
gen_addr_imm_index(ctx, t0, 0);
|
||||
gen_qemu_ld64_i64(ctx, t2, t0);
|
||||
set_fpr(rd, t2);
|
||||
gen_addr_add(ctx, t1, t0, 8);
|
||||
gen_qemu_ld64_i64(ctx, t2, t1);
|
||||
set_fpr((rd + 1) % 32, t2);
|
||||
if (ra != 0) {
|
||||
tcg_gen_mov_tl(cpu_gpr[ra], t0);
|
||||
}
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free_i64(t2);
|
||||
}
|
||||
|
||||
/* lfqux */
|
||||
static void gen_lfqux(DisasContext *ctx)
|
||||
{
|
||||
int ra = rA(ctx->opcode);
|
||||
int rd = rD(ctx->opcode);
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
TCGv t0, t1;
|
||||
TCGv_i64 t2;
|
||||
t2 = tcg_temp_new_i64();
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
gen_qemu_ld64_i64(ctx, t2, t0);
|
||||
set_fpr(rd, t2);
|
||||
t1 = tcg_temp_new();
|
||||
gen_addr_add(ctx, t1, t0, 8);
|
||||
gen_qemu_ld64_i64(ctx, t2, t1);
|
||||
set_fpr((rd + 1) % 32, t2);
|
||||
tcg_temp_free(t1);
|
||||
if (ra != 0) {
|
||||
tcg_gen_mov_tl(cpu_gpr[ra], t0);
|
||||
}
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t2);
|
||||
}
|
||||
|
||||
/* lfqx */
|
||||
static void gen_lfqx(DisasContext *ctx)
|
||||
{
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0;
|
||||
TCGv_i64 t1;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
gen_qemu_ld64_i64(ctx, t1, t0);
|
||||
set_fpr(rd, t1);
|
||||
gen_addr_add(ctx, t0, t0, 8);
|
||||
gen_qemu_ld64_i64(ctx, t1, t0);
|
||||
set_fpr((rd + 1) % 32, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
|
||||
/* stfq */
|
||||
static void gen_stfq(DisasContext *ctx)
|
||||
{
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0;
|
||||
TCGv_i64 t1;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_addr_imm_index(ctx, t0, 0);
|
||||
get_fpr(t1, rd);
|
||||
gen_qemu_st64_i64(ctx, t1, t0);
|
||||
gen_addr_add(ctx, t0, t0, 8);
|
||||
get_fpr(t1, (rd + 1) % 32);
|
||||
gen_qemu_st64_i64(ctx, t1, t0);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
|
||||
/* stfqu */
|
||||
static void gen_stfqu(DisasContext *ctx)
|
||||
{
|
||||
int ra = rA(ctx->opcode);
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0, t1;
|
||||
TCGv_i64 t2;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t2 = tcg_temp_new_i64();
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_imm_index(ctx, t0, 0);
|
||||
get_fpr(t2, rd);
|
||||
gen_qemu_st64_i64(ctx, t2, t0);
|
||||
t1 = tcg_temp_new();
|
||||
gen_addr_add(ctx, t1, t0, 8);
|
||||
get_fpr(t2, (rd + 1) % 32);
|
||||
gen_qemu_st64_i64(ctx, t2, t1);
|
||||
tcg_temp_free(t1);
|
||||
if (ra != 0) {
|
||||
tcg_gen_mov_tl(cpu_gpr[ra], t0);
|
||||
}
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t2);
|
||||
}
|
||||
|
||||
/* stfqux */
|
||||
static void gen_stfqux(DisasContext *ctx)
|
||||
{
|
||||
int ra = rA(ctx->opcode);
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0, t1;
|
||||
TCGv_i64 t2;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t2 = tcg_temp_new_i64();
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
get_fpr(t2, rd);
|
||||
gen_qemu_st64_i64(ctx, t2, t0);
|
||||
t1 = tcg_temp_new();
|
||||
gen_addr_add(ctx, t1, t0, 8);
|
||||
get_fpr(t2, (rd + 1) % 32);
|
||||
gen_qemu_st64_i64(ctx, t2, t1);
|
||||
tcg_temp_free(t1);
|
||||
if (ra != 0) {
|
||||
tcg_gen_mov_tl(cpu_gpr[ra], t0);
|
||||
}
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t2);
|
||||
}
|
||||
|
||||
/* stfqx */
|
||||
static void gen_stfqx(DisasContext *ctx)
|
||||
{
|
||||
int rd = rD(ctx->opcode);
|
||||
TCGv t0;
|
||||
TCGv_i64 t1;
|
||||
gen_set_access_type(ctx, ACCESS_FLOAT);
|
||||
t1 = tcg_temp_new_i64();
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
get_fpr(t1, rd);
|
||||
gen_qemu_st64_i64(ctx, t1, t0);
|
||||
gen_addr_add(ctx, t0, t0, 8);
|
||||
get_fpr(t1, (rd + 1) % 32);
|
||||
gen_qemu_st64_i64(ctx, t1, t0);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
|
||||
/* Floating-point Load/Store Instructions */
|
||||
static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ,
|
||||
bool update, bool store, bool single)
|
||||
|
|
|
@ -747,6 +747,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
|
|||
} \
|
||||
} \
|
||||
set_cpu_vsr(xT(ctx->opcode), xb, true); \
|
||||
set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \
|
||||
tcg_temp_free_i64(xb); \
|
||||
tcg_temp_free_i64(sgm); \
|
||||
}
|
||||
|
@ -1073,6 +1074,7 @@ static void gen_##name(DisasContext *ctx) \
|
|||
get_cpu_vsr(t0, xB(ctx->opcode), true); \
|
||||
gen_helper_##name(t1, cpu_env, t0); \
|
||||
set_cpu_vsr(xT(ctx->opcode), t1, true); \
|
||||
set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \
|
||||
tcg_temp_free_i64(t0); \
|
||||
tcg_temp_free_i64(t1); \
|
||||
}
|
||||
|
@ -1700,7 +1702,7 @@ static void gen_xsiexpdp(DisasContext *ctx)
|
|||
tcg_gen_shli_i64(t0, t0, 52);
|
||||
tcg_gen_or_i64(xth, xth, t0);
|
||||
set_cpu_vsr(xT(ctx->opcode), xth, true);
|
||||
/* dword[1] is undefined */
|
||||
set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(xth);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue