ppc 7.0 queue:

* Exception and TLB fixes for the 405 CPU (Fabiano and Cedric)
 * spapr fixes (Alexey and Daniel)
 * PowerNV PHB3/4 fixes (Frederic and Daniel)
 * PowerNV XIVE improvements (Cedric)
 * 603 CPUs fixes (Christophe)
 * Book-E exception fixes (Vitaly)
 * Misc compile issues  (Philippe and Fabiano)
 * Exception model rework for the BookS CPUs (Fabiano)
 * Exception model rework for the 74xx CPUs (Fabiano)
 * Removal of 602 CPUs
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmH2zf8ACgkQUaNDx8/7
 7KFRpw//XIf99FI9/2LkovsEQIrQ8CooRfOO/4u37tU0W9uxANGrHjx47sANYcwD
 T45pH44++CjJwvEdwZmLEVicfvGzRVarZct3RofH0oqpYQVSdJNN4azmBHkhFBxN
 1ygdppilu/6UVLRyqtiSykv2aoG5KNhLLoxR7Y2SHapnxs4Nnk5dn0QJcc7N/EpN
 RZ4a3dP+L4MWyZ3rZ0Yy3MXumaC+Sh6b9lxxZUBVNrPWR38zew3iFLy7A9kqCDfi
 FG/MSdIjctgF31ZKc91OxNwQDok3ByNrPLVTWhsNmNAdTqHEEmG58oDZAdDUo0Yg
 dzqmiUXglvWe4O54giLCBhDgF9EbWgsg2Bwu46w3+yugnTFAF6ESnngDXeu09zjW
 qlqNe2xajgY7tWCuJi/OGoPq14S7lzfIki5wSO1fWiHZR9qlfYWP7E5gYVtRYtaZ
 JG/+gcRoQSPfWP0LY/qazuQPtB8ha5pFwTWQlAATeHl3nfEqQAZmEuLUAdmtTaZx
 Pm5fEH12tnolLgf3DIAh247CZR4m5gl3MpQEhJzyCYJBEtbQfQv403BvyBIm8qDj
 BER/gBiscTQMKSnzoZ8ooKMqcIfnCvGtY8E6hn4uvRcAJ1Uz5DGRylQ6ySzy/JJt
 plW5XuKoBWfWYsQxe9PSoPtMXbCwEd4aQEbBR5e6akBJSrrtP0U=
 =qP5f
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/legoater/tags/pull-ppc-20220130' into staging

ppc 7.0 queue:

* Exception and TLB fixes for the 405 CPU (Fabiano and Cedric)
* spapr fixes (Alexey and Daniel)
* PowerNV PHB3/4 fixes (Frederic and Daniel)
* PowerNV XIVE improvements (Cedric)
* 603 CPUs fixes (Christophe)
* Book-E exception fixes (Vitaly)
* Misc compile issues  (Philippe and Fabiano)
* Exception model rework for the BookS CPUs (Fabiano)
* Exception model rework for the 74xx CPUs (Fabiano)
* Removal of 602 CPUs

# gpg: Signature made Sun 30 Jan 2022 17:42:23 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-20220130: (41 commits)
  target/ppc: Remove support for the PowerPC 602 CPU
  target/ppc: 74xx: Set SRRs directly in exception code
  target/ppc: 74xx: System Reset interrupt cleanup
  target/ppc: 74xx: System Call exception cleanup
  target/ppc: 74xx: Program exception cleanup
  target/ppc: 74xx: External interrupt cleanup
  target/ppc: 74xx: Machine Check exception cleanup
  target/ppc: Simplify powerpc_excp_74xx
  target/ppc: Introduce powerpc_excp_74xx
  target/ppc: books: Program exception cleanup
  target/ppc: books: External interrupt cleanup
  target/ppc: books: Machine Check exception cleanup
  target/ppc: Simplify powerpc_excp_books
  target/ppc: Introduce powerpc_excp_books
  target/ppc: 405: Watchdog timer exception cleanup
  target/ppc: 405: Program exception cleanup
  target/ppc: 405: Instruction storage interrupt cleanup
  target/ppc: 405: Data Storage exception cleanup
  target/ppc: 405: Debug exception cleanup
  target/ppc: 405: Alignment exception cleanup
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-01-31 11:10:07 +00:00
commit 804b30d25f
21 changed files with 761 additions and 355 deletions

View File

@ -172,7 +172,12 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
/* Get the page size of the indirect table. */ /* Get the page size of the indirect table. */
vsd_addr = vsd & VSD_ADDRESS_MASK; vsd_addr = vsd & VSD_ADDRESS_MASK;
ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED); if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
MEMTXATTRS_UNSPECIFIED)) {
xive_error(xive, "VST: failed to access %s entry %x @0x%" PRIx64,
info->name, idx, vsd_addr);
return 0;
}
if (!(vsd & VSD_ADDRESS_MASK)) { if (!(vsd & VSD_ADDRESS_MASK)) {
#ifdef XIVE_DEBUG #ifdef XIVE_DEBUG
@ -195,8 +200,12 @@ static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
/* Load the VSD we are looking for, if not already done */ /* Load the VSD we are looking for, if not already done */
if (vsd_idx) { if (vsd_idx) {
vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE; vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
ldq_be_dma(&address_space_memory, vsd_addr, &vsd, if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
MEMTXATTRS_UNSPECIFIED); MEMTXATTRS_UNSPECIFIED)) {
xive_error(xive, "VST: failed to access %s entry %x @0x%"
PRIx64, info->name, vsd_idx, vsd_addr);
return 0;
}
if (!(vsd & VSD_ADDRESS_MASK)) { if (!(vsd & VSD_ADDRESS_MASK)) {
#ifdef XIVE_DEBUG #ifdef XIVE_DEBUG
@ -543,7 +552,12 @@ static uint64_t pnv_xive_vst_per_subpage(PnvXive *xive, uint32_t type)
/* Get the page size of the indirect table. */ /* Get the page size of the indirect table. */
vsd_addr = vsd & VSD_ADDRESS_MASK; vsd_addr = vsd & VSD_ADDRESS_MASK;
ldq_be_dma(&address_space_memory, vsd_addr, &vsd, MEMTXATTRS_UNSPECIFIED); if (ldq_be_dma(&address_space_memory, vsd_addr, &vsd,
MEMTXATTRS_UNSPECIFIED)) {
xive_error(xive, "VST: failed to access %s entry @0x%" PRIx64,
info->name, vsd_addr);
return 0;
}
if (!(vsd & VSD_ADDRESS_MASK)) { if (!(vsd & VSD_ADDRESS_MASK)) {
#ifdef XIVE_DEBUG #ifdef XIVE_DEBUG

View File

@ -792,7 +792,9 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr,
sh = tbl_shift * lev + tce_shift; sh = tbl_shift * lev + tce_shift;
/* TODO: Multi-level untested */ /* TODO: Multi-level untested */
while ((lev--) >= 0) { do {
lev--;
/* Grab the TCE address */ /* Grab the TCE address */
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3); taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
if (dma_memory_read(&address_space_memory, taddr, &tce, if (dma_memory_read(&address_space_memory, taddr, &tce,
@ -813,21 +815,22 @@ static void pnv_phb3_translate_tve(PnvPhb3DMASpace *ds, hwaddr addr,
} }
sh -= tbl_shift; sh -= tbl_shift;
base = tce & ~0xfffull; base = tce & ~0xfffull;
} } while (lev >= 0);
/* We exit the loop with TCE being the final TCE */ /* We exit the loop with TCE being the final TCE */
tce_mask = ~((1ull << tce_shift) - 1);
tlb->iova = addr & tce_mask;
tlb->translated_addr = tce & tce_mask;
tlb->addr_mask = ~tce_mask;
tlb->perm = tce & 3;
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) { if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
phb3_error(phb, "TCE access fault at 0x%"PRIx64, taddr); phb3_error(phb, "TCE access fault at 0x%"PRIx64, taddr);
phb3_error(phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr, phb3_error(phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
is_write ? 'W' : 'R', tve); is_write ? 'W' : 'R', tve);
phb3_error(phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d", phb3_error(phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
tta, lev, tts, tps); tta, lev, tts, tps);
return;
} }
tce_mask = ~((1ull << tce_shift) - 1);
tlb->iova = addr & tce_mask;
tlb->translated_addr = tce & tce_mask;
tlb->addr_mask = ~tce_mask;
tlb->perm = tce & 3;
} }
} }

View File

@ -1267,7 +1267,9 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr,
/* TODO: Limit to support IO page sizes */ /* TODO: Limit to support IO page sizes */
/* TODO: Multi-level untested */ /* TODO: Multi-level untested */
while ((lev--) >= 0) { do {
lev--;
/* Grab the TCE address */ /* Grab the TCE address */
taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3); taddr = base | (((addr >> sh) & ((1ul << tbl_shift) - 1)) << 3);
if (dma_memory_read(&address_space_memory, taddr, &tce, if (dma_memory_read(&address_space_memory, taddr, &tce,
@ -1288,21 +1290,22 @@ static void pnv_phb4_translate_tve(PnvPhb4DMASpace *ds, hwaddr addr,
} }
sh -= tbl_shift; sh -= tbl_shift;
base = tce & ~0xfffull; base = tce & ~0xfffull;
} } while (lev >= 0);
/* We exit the loop with TCE being the final TCE */ /* We exit the loop with TCE being the final TCE */
tce_mask = ~((1ull << tce_shift) - 1);
tlb->iova = addr & tce_mask;
tlb->translated_addr = tce & tce_mask;
tlb->addr_mask = ~tce_mask;
tlb->perm = tce & 3;
if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) { if ((is_write & !(tce & 2)) || ((!is_write) && !(tce & 1))) {
phb_error(ds->phb, "TCE access fault at 0x%"PRIx64, taddr); phb_error(ds->phb, "TCE access fault at 0x%"PRIx64, taddr);
phb_error(ds->phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr, phb_error(ds->phb, " xlate %"PRIx64":%c TVE=%"PRIx64, addr,
is_write ? 'W' : 'R', tve); is_write ? 'W' : 'R', tve);
phb_error(ds->phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d", phb_error(ds->phb, " tta=%"PRIx64" lev=%d tts=%d tps=%d",
tta, lev, tts, tps); tta, lev, tts, tps);
return;
} }
tce_mask = ~((1ull << tce_shift) - 1);
tlb->iova = addr & tce_mask;
tlb->translated_addr = tce & tce_mask;
tlb->addr_mask = ~tce_mask;
tlb->perm = tce & 3;
} }
} }

View File

@ -3053,7 +3053,7 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON); VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE); PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);
if (d) { if (d && bus) {
void *spapr = CAST(void, bus->parent, "spapr-vscsi"); void *spapr = CAST(void, bus->parent, "spapr-vscsi");
VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI); VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE); USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);

View File

@ -37,6 +37,11 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
cpu_reset(cs); cpu_reset(cs);
/*
* "PowerPC Processor binding to IEEE 1275" defines the initial MSR state
* as 32bit (MSR_SF=0) in "8.2.1. Initial Register Values".
*/
env->msr &= ~(1ULL << MSR_SF);
env->spr[SPR_HIOR] = 0; env->spr[SPR_HIOR] = 0;
lpcr = env->spr[SPR_LPCR]; lpcr = env->spr[SPR_LPCR];

View File

@ -88,8 +88,6 @@ void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
stack_ptr, spapr->initrd_base, stack_ptr, spapr->initrd_base,
spapr->initrd_size); spapr->initrd_size);
/* VOF is 32bit BE so enforce MSR here */
first_ppc_cpu->env.msr &= ~((1ULL << MSR_SF) | (1ULL << MSR_LE));
/* /*
* At this point the expected allocation map is: * At this point the expected allocation map is:

View File

@ -16,7 +16,6 @@
#include "qemu/units.h" #include "qemu/units.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "exec/ram_addr.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "hw/ppc/vof.h" #include "hw/ppc/vof.h"
#include "hw/ppc/fdt.h" #include "hw/ppc/fdt.h"

View File

@ -6,6 +6,11 @@
#ifndef HW_VOF_H #ifndef HW_VOF_H
#define HW_VOF_H #define HW_VOF_H
#include "qom/object.h"
#include "exec/address-spaces.h"
#include "exec/memory.h"
#include "cpu.h"
typedef struct Vof { typedef struct Vof {
uint64_t top_addr; /* copied from rma_size */ uint64_t top_addr; /* copied from rma_size */
GArray *claimed; /* array of SpaprOfClaimed */ GArray *claimed; /* array of SpaprOfClaimed */

View File

@ -428,8 +428,6 @@
"PowerPC 601v1") "PowerPC 601v1")
POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v, POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v,
"PowerPC 601v2") "PowerPC 601v2")
POWERPC_DEF("602", CPU_POWERPC_602, 602,
"PowerPC 602")
POWERPC_DEF("603", CPU_POWERPC_603, 603, POWERPC_DEF("603", CPU_POWERPC_603, 603,
"PowerPC 603") "PowerPC 603")
POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E, POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E,

View File

@ -208,7 +208,6 @@ enum {
CPU_POWERPC_601_v0 = 0x00010001, CPU_POWERPC_601_v0 = 0x00010001,
CPU_POWERPC_601_v1 = 0x00010001, CPU_POWERPC_601_v1 = 0x00010001,
CPU_POWERPC_601_v2 = 0x00010002, CPU_POWERPC_601_v2 = 0x00010002,
CPU_POWERPC_602 = 0x00050100,
CPU_POWERPC_603 = 0x00030100, CPU_POWERPC_603 = 0x00030100,
CPU_POWERPC_603E_v11 = 0x00060101, CPU_POWERPC_603E_v11 = 0x00060101,
CPU_POWERPC_603E_v12 = 0x00060102, CPU_POWERPC_603E_v12 = 0x00060102,

View File

@ -321,12 +321,11 @@ typedef enum {
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ #define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
#define MSR_VR 25 /* altivec available x hflags */ #define MSR_VR 25 /* altivec available x hflags */
#define MSR_SPE 25 /* SPE enable for BookE x hflags */ #define MSR_SPE 25 /* SPE enable for BookE x hflags */
#define MSR_AP 23 /* Access privilege state on 602 hflags */
#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */ #define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */
#define MSR_SA 22 /* Supervisor access mode on 602 hflags */
#define MSR_S 22 /* Secure state */ #define MSR_S 22 /* Secure state */
#define MSR_KEY 19 /* key bit on 603e */ #define MSR_KEY 19 /* key bit on 603e */
#define MSR_POW 18 /* Power management */ #define MSR_POW 18 /* Power management */
#define MSR_WE 18 /* Wait State Enable on 405 */
#define MSR_TGPR 17 /* TGPR usage on 602/603 x */ #define MSR_TGPR 17 /* TGPR usage on 602/603 x */
#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */ #define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */
#define MSR_ILE 16 /* Interrupt little-endian mode */ #define MSR_ILE 16 /* Interrupt little-endian mode */
@ -476,9 +475,7 @@ typedef enum {
#define msr_ucle ((env->msr >> MSR_UCLE) & 1) #define msr_ucle ((env->msr >> MSR_UCLE) & 1)
#define msr_vr ((env->msr >> MSR_VR) & 1) #define msr_vr ((env->msr >> MSR_VR) & 1)
#define msr_spe ((env->msr >> MSR_SPE) & 1) #define msr_spe ((env->msr >> MSR_SPE) & 1)
#define msr_ap ((env->msr >> MSR_AP) & 1)
#define msr_vsx ((env->msr >> MSR_VSX) & 1) #define msr_vsx ((env->msr >> MSR_VSX) & 1)
#define msr_sa ((env->msr >> MSR_SA) & 1)
#define msr_key ((env->msr >> MSR_KEY) & 1) #define msr_key ((env->msr >> MSR_KEY) & 1)
#define msr_pow ((env->msr >> MSR_POW) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1)
#define msr_tgpr ((env->msr >> MSR_TGPR) & 1) #define msr_tgpr ((env->msr >> MSR_TGPR) & 1)
@ -2141,8 +2138,6 @@ enum {
PPC_MFTB = 0x0000000000000200ULL, PPC_MFTB = 0x0000000000000200ULL,
/* Fixed-point unit extensions */ /* Fixed-point unit extensions */
/* PowerPC 602 specific */
PPC_602_SPEC = 0x0000000000000400ULL,
/* isel instruction */ /* isel instruction */
PPC_ISEL = 0x0000000000000800ULL, PPC_ISEL = 0x0000000000000800ULL,
/* popcntb instruction */ /* popcntb instruction */
@ -2244,7 +2239,7 @@ enum {
#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \ #define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
| PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \ | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
| PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \ | PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
| PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \ | PPC_ISEL | PPC_POPCNTB \
| PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \ | PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
| PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \ | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \
| PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \ | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \

View File

@ -749,54 +749,6 @@ static void register_G2_sprs(CPUPPCState *env)
0x00000000); 0x00000000);
} }
/* SPR specific to PowerPC 602 implementation */
static void register_602_sprs(CPUPPCState *env)
{
/* ESA registers */
/* XXX : not implemented */
spr_register(env, SPR_SER, "SER",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_SEBR, "SEBR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_ESASRR, "ESASRR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Floating point status */
/* XXX : not implemented */
spr_register(env, SPR_SP, "SP",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_LT, "LT",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Watchdog timer */
/* XXX : not implemented */
spr_register(env, SPR_TCR, "TCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Interrupt base */
spr_register(env, SPR_IBR, "IBR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR specific to PowerPC 601 implementation */ /* SPR specific to PowerPC 601 implementation */
static void register_601_sprs(CPUPPCState *env) static void register_601_sprs(CPUPPCState *env)
{ {
@ -2128,33 +2080,6 @@ static void init_excp_601(CPUPPCState *env)
#endif #endif
} }
static void init_excp_602(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/* XXX: exception prefix has a special behavior on 602 */
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_SYSCALL] = 0x00000C00;
env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00;
env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000;
env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100;
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500;
env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600;
/* Hardware reset vector */
env->hreset_vector = 0x00000100UL;
#endif
}
static void init_excp_603(CPUPPCState *env) static void init_excp_603(CPUPPCState *env)
{ {
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
@ -2535,11 +2460,12 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC |
PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP; PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP;
pcc->msr_mask = (1ull << MSR_POW) | pcc->msr_mask = (1ull << MSR_WE) |
(1ull << MSR_CE) | (1ull << MSR_CE) |
(1ull << MSR_EE) | (1ull << MSR_EE) |
(1ull << MSR_PR) | (1ull << MSR_PR) |
(1ull << MSR_FP) | (1ull << MSR_FP) |
(1ull << MSR_ME) |
(1ull << MSR_DWE) | (1ull << MSR_DWE) |
(1ull << MSR_DE) | (1ull << MSR_DE) |
(1ull << MSR_IR) | (1ull << MSR_IR) |
@ -4080,76 +4006,6 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
} }
static void init_proc_602(CPUPPCState *env)
{
register_ne_601_sprs(env);
register_sdr1_sprs(env);
register_602_sprs(env);
/* Time base */
register_tbl(env);
/* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_HID1, "HID1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
register_low_BATs(env);
register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_602(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
/* Allocate hardware IRQ controller */
ppc6xx_irq_init(env_archcpu(env));
}
POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->desc = "PowerPC 602";
pcc->init_proc = init_proc_602;
pcc->check_pow = check_pow_hid0;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC |
PPC_SEGMENT | PPC_602_SPEC;
pcc->msr_mask = (1ull << MSR_VSX) |
(1ull << MSR_SA) |
(1ull << MSR_POW) |
(1ull << MSR_TGPR) |
(1ull << MSR_ILE) |
(1ull << MSR_EE) |
(1ull << MSR_PR) |
(1ull << MSR_FP) |
(1ull << MSR_ME) |
(1ull << MSR_FE0) |
(1ull << MSR_SE) |
(1ull << MSR_DE) |
(1ull << MSR_FE1) |
(1ull << MSR_EP) |
(1ull << MSR_IR) |
(1ull << MSR_DR) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
/* XXX: 602 MMU is quite specific. Should add a special case */
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
pcc->excp_model = POWERPC_EXCP_602;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_602;
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK;
}
static void init_proc_603(CPUPPCState *env) static void init_proc_603(CPUPPCState *env)
{ {
register_ne_601_sprs(env); register_ne_601_sprs(env);
@ -8270,8 +8126,6 @@ static void ppc_cpu_reset(DeviceState *dev)
msr = (target_ulong)0; msr = (target_ulong)0;
msr |= (target_ulong)MSR_HVB; msr |= (target_ulong)MSR_HVB;
msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
msr |= (target_ulong)1 << MSR_EP; msr |= (target_ulong)1 << MSR_EP;
#if defined(DO_SINGLE_STEP) && 0 #if defined(DO_SINGLE_STEP) && 0
/* Single step trace mode */ /* Single step trace mode */

View File

@ -392,6 +392,660 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu,
check_tlb_flush(env, false); check_tlb_flush(env, false);
} }
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
int srr0, srr1;
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
}
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
excp, env->error_code);
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
/*
* new interrupt handler msr preserves existing ME unless
* explicitly overriden.
*/
new_msr = env->msr & (((target_ulong)1 << MSR_ME));
/* target registers */
srr0 = SPR_SRR0;
srr1 = SPR_SRR1;
/*
* Hypervisor emulation assistance interrupt only exists on server
* arch 2.05 server or later.
*/
if (excp == POWERPC_EXCP_HV_EMU) {
excp = POWERPC_EXCP_PROGRAM;
}
vector = env->excp_vectors[excp];
if (vector == (target_ulong)-1ULL) {
cpu_abort(cs, "Raised an exception without defined vector %d\n",
excp);
}
vector |= env->excp_prefix;
switch (excp) {
case POWERPC_EXCP_CRITICAL: /* Critical input */
srr0 = SPR_40x_SRR2;
srr1 = SPR_40x_SRR3;
break;
case POWERPC_EXCP_MCHECK: /* Machine check exception */
if (msr_me == 0) {
/*
* Machine check exception is not enabled. Enter
* checkstop state.
*/
fprintf(stderr, "Machine check while not allowed. "
"Entering checkstop state\n");
if (qemu_log_separate()) {
qemu_log("Machine check while not allowed. "
"Entering checkstop state\n");
}
cs->halted = 1;
cpu_interrupt_exittb(cs);
}
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
srr0 = SPR_40x_SRR2;
srr1 = SPR_40x_SRR3;
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
trace_ppc_excp_isi(msr, env->nip);
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
break;
case POWERPC_EXCP_ALIGN: /* Alignment exception */
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
trace_ppc_excp_fp_ignore();
cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
return;
}
env->spr[SPR_40x_ESR] = ESR_FP;
break;
case POWERPC_EXCP_INVAL:
trace_ppc_excp_inval(env->nip);
env->spr[SPR_40x_ESR] = ESR_PIL;
break;
case POWERPC_EXCP_PRIV:
env->spr[SPR_40x_ESR] = ESR_PPR;
break;
case POWERPC_EXCP_TRAP:
env->spr[SPR_40x_ESR] = ESR_PTR;
break;
default:
cpu_abort(cs, "Invalid program exception %d. Aborting\n",
env->error_code);
break;
}
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
dump_syscall(env);
/*
* We need to correct the NIP which in this case is supposed
* to point to the next instruction
*/
env->nip += 4;
break;
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
trace_ppc_excp_print("FIT");
break;
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
trace_ppc_excp_print("WDT");
break;
case POWERPC_EXCP_DTLB: /* Data TLB error */
case POWERPC_EXCP_ITLB: /* Instruction TLB error */
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
trace_ppc_excp_print("PIT");
break;
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
cpu_abort(cs, "%s exception not implemented\n",
powerpc_excp_name(excp));
break;
default:
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
break;
}
/* Sanity check */
if (!(env->msr_mask & MSR_HVB)) {
if (new_msr & MSR_HVB) {
cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
"no HV support\n", excp);
}
if (srr0 == SPR_HSRR0) {
cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
"no HV support\n", excp);
}
}
/* Save PC */
env->spr[srr0] = env->nip;
/* Save MSR */
env->spr[srr1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
}
static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
}
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
excp, env->error_code);
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
/*
* new interrupt handler msr preserves existing ME unless
* explicitly overriden
*/
new_msr = env->msr & ((target_ulong)1 << MSR_ME);
/*
* Hypervisor emulation assistance interrupt only exists on server
* arch 2.05 server or later.
*/
if (excp == POWERPC_EXCP_HV_EMU) {
excp = POWERPC_EXCP_PROGRAM;
}
vector = env->excp_vectors[excp];
if (vector == (target_ulong)-1ULL) {
cpu_abort(cs, "Raised an exception without defined vector %d\n",
excp);
}
vector |= env->excp_prefix;
switch (excp) {
case POWERPC_EXCP_MCHECK: /* Machine check exception */
if (msr_me == 0) {
/*
* Machine check exception is not enabled. Enter
* checkstop state.
*/
fprintf(stderr, "Machine check while not allowed. "
"Entering checkstop state\n");
if (qemu_log_separate()) {
qemu_log("Machine check while not allowed. "
"Entering checkstop state\n");
}
cs->halted = 1;
cpu_interrupt_exittb(cs);
}
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
trace_ppc_excp_isi(msr, env->nip);
msr |= env->error_code;
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
break;
case POWERPC_EXCP_ALIGN: /* Alignment exception */
/* Get rS/rD and rA from faulting opcode */
/*
* Note: the opcode fields will not be set properly for a
* direct store load/store, but nobody cares as nobody
* actually uses direct store segments.
*/
env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
trace_ppc_excp_fp_ignore();
cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
return;
}
/*
* FP exceptions always have NIP pointing to the faulting
* instruction, so always use store_next and claim we are
* precise in the MSR.
*/
msr |= 0x00100000;
break;
case POWERPC_EXCP_INVAL:
trace_ppc_excp_inval(env->nip);
msr |= 0x00080000;
break;
case POWERPC_EXCP_PRIV:
msr |= 0x00040000;
break;
case POWERPC_EXCP_TRAP:
msr |= 0x00020000;
break;
default:
/* Should never occur */
cpu_abort(cs, "Invalid program exception %d. Aborting\n",
env->error_code);
break;
}
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
{
int lev = env->error_code;
if ((lev == 1) && cpu->vhyp) {
dump_hcall(env);
} else {
dump_syscall(env);
}
/*
* We need to correct the NIP which in this case is supposed
* to point to the next instruction
*/
env->nip += 4;
/*
* The Virtual Open Firmware (VOF) relies on the 'sc 1'
* instruction to communicate with QEMU. The pegasos2 machine
* uses VOF and the 74xx CPUs, so although the 74xx don't have
* HV mode, we need to keep hypercall support.
*/
if ((lev == 1) && cpu->vhyp) {
PPCVirtualHypervisorClass *vhc =
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
return;
}
break;
}
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
case POWERPC_EXCP_DECR: /* Decrementer exception */
break;
case POWERPC_EXCP_RESET: /* System reset exception */
if (msr_pow) {
cpu_abort(cs, "Trying to deliver power-saving system reset "
"exception %d with no HV support\n", excp);
}
break;
case POWERPC_EXCP_TRACE: /* Trace exception */
break;
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
break;
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
case POWERPC_EXCP_SMI: /* System management interrupt */
case POWERPC_EXCP_THERM: /* Thermal interrupt */
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
case POWERPC_EXCP_VPUA: /* Vector assist exception */
cpu_abort(cs, "%s exception not implemented\n",
powerpc_excp_name(excp));
break;
default:
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
break;
}
/* Sanity check */
if (!(env->msr_mask & MSR_HVB)) {
if (new_msr & MSR_HVB) {
cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
"no HV support\n", excp);
}
}
/*
* Sort out endianness of interrupt, this differs depending on the
* CPU, the HV mode, etc...
*/
if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
new_msr |= (target_ulong)1 << MSR_LE;
}
/* Save PC */
env->spr[SPR_SRR0] = env->nip;
/* Save MSR */
env->spr[SPR_SRR1] = msr;
powerpc_set_excp_state(cpu, vector, new_msr);
}
#ifdef TARGET_PPC64
static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
int excp_model = env->excp_model;
target_ulong msr, new_msr, vector;
int srr0, srr1, lev = -1;
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
}
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
excp, env->error_code);
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
/*
* new interrupt handler msr preserves existing HV and ME unless
* explicitly overriden
*/
new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
/* target registers */
srr0 = SPR_SRR0;
srr1 = SPR_SRR1;
/*
* check for special resume at 0x100 from doze/nap/sleep/winkle on
* P7/P8/P9
*/
if (env->resume_as_sreset) {
excp = powerpc_reset_wakeup(cs, env, excp, &msr);
}
/*
* We don't want to generate a Hypervisor Emulation Assistance
* Interrupt if we don't have HVB in msr_mask (PAPR mode).
*/
if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
excp = POWERPC_EXCP_PROGRAM;
}
vector = env->excp_vectors[excp];
if (vector == (target_ulong)-1ULL) {
cpu_abort(cs, "Raised an exception without defined vector %d\n",
excp);
}
vector |= env->excp_prefix;
switch (excp) {
case POWERPC_EXCP_MCHECK: /* Machine check exception */
if (msr_me == 0) {
/*
* Machine check exception is not enabled. Enter
* checkstop state.
*/
fprintf(stderr, "Machine check while not allowed. "
"Entering checkstop state\n");
if (qemu_log_separate()) {
qemu_log("Machine check while not allowed. "
"Entering checkstop state\n");
}
cs->halted = 1;
cpu_interrupt_exittb(cs);
}
if (env->msr_mask & MSR_HVB) {
/*
* ISA specifies HV, but can be delivered to guest with HV
* clear (e.g., see FWNMI in PAPR).
*/
new_msr |= (target_ulong)MSR_HVB;
}
/* machine check exceptions don't have ME set */
new_msr &= ~((target_ulong)1 << MSR_ME);
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
trace_ppc_excp_isi(msr, env->nip);
msr |= env->error_code;
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
{
bool lpes0;
/*
* LPES0 is only taken into consideration if we support HV
* mode for this CPU.
*/
if (!env->has_hv_mode) {
break;
}
lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
if (!lpes0) {
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
}
break;
}
case POWERPC_EXCP_ALIGN: /* Alignment exception */
/* Get rS/rD and rA from faulting opcode */
/*
* Note: the opcode fields will not be set properly for a
* direct store load/store, but nobody cares as nobody
* actually uses direct store segments.
*/
env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
trace_ppc_excp_fp_ignore();
cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
return;
}
/*
* FP exceptions always have NIP pointing to the faulting
* instruction, so always use store_next and claim we are
* precise in the MSR.
*/
msr |= 0x00100000;
break;
case POWERPC_EXCP_INVAL:
trace_ppc_excp_inval(env->nip);
msr |= 0x00080000;
break;
case POWERPC_EXCP_PRIV:
msr |= 0x00040000;
break;
case POWERPC_EXCP_TRAP:
msr |= 0x00020000;
break;
default:
/* Should never occur */
cpu_abort(cs, "Invalid program exception %d. Aborting\n",
env->error_code);
break;
}
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
lev = env->error_code;
if ((lev == 1) && cpu->vhyp) {
dump_hcall(env);
} else {
dump_syscall(env);
}
/*
* We need to correct the NIP which in this case is supposed
* to point to the next instruction
*/
env->nip += 4;
/* "PAPR mode" built-in hypercall emulation */
if ((lev == 1) && cpu->vhyp) {
PPCVirtualHypervisorClass *vhc =
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
return;
}
if (lev == 1) {
new_msr |= (target_ulong)MSR_HVB;
}
break;
case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
lev = env->error_code;
dump_syscall(env);
env->nip += 4;
new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
vector += lev * 0x20;
env->lr = env->nip;
env->ctr = msr;
break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
case POWERPC_EXCP_DECR: /* Decrementer exception */
break;
case POWERPC_EXCP_RESET: /* System reset exception */
/* A power-saving exception sets ME, otherwise it is unchanged */
if (msr_pow) {
/* indicate that we resumed from power save mode */
msr |= 0x10000;
new_msr |= ((target_ulong)1 << MSR_ME);
}
if (env->msr_mask & MSR_HVB) {
/*
* ISA specifies HV, but can be delivered to guest with HV
* clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
*/
new_msr |= (target_ulong)MSR_HVB;
} else {
if (msr_pow) {
cpu_abort(cs, "Trying to deliver power-saving system reset "
"exception %d with no HV support\n", excp);
}
}
break;
case POWERPC_EXCP_DSEG: /* Data segment exception */
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
case POWERPC_EXCP_TRACE: /* Trace exception */
break;
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
msr |= env->error_code;
/* fall through */
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */
case POWERPC_EXCP_HV_EMU:
case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
break;
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
case POWERPC_EXCP_FU: /* Facility unavailable exception */
env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
break;
case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */
env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
break;
case POWERPC_EXCP_THERM: /* Thermal interrupt */
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
case POWERPC_EXCP_VPUA: /* Vector assist exception */
case POWERPC_EXCP_MAINT: /* Maintenance exception */
case POWERPC_EXCP_SDOOR: /* Doorbell interrupt */
case POWERPC_EXCP_HV_MAINT: /* Hypervisor Maintenance exception */
cpu_abort(cs, "%s exception not implemented\n",
powerpc_excp_name(excp));
break;
default:
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
break;
}
/* Sanity check */
if (!(env->msr_mask & MSR_HVB)) {
if (new_msr & MSR_HVB) {
cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
"no HV support\n", excp);
}
if (srr0 == SPR_HSRR0) {
cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
"no HV support\n", excp);
}
}
/*
* Sort out endianness of interrupt, this differs depending on the
* CPU, the HV mode, etc...
*/
if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
new_msr |= (target_ulong)1 << MSR_LE;
}
new_msr |= (target_ulong)1 << MSR_SF;
if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
/* Save PC */
env->spr[srr0] = env->nip;
/* Save MSR */
env->spr[srr1] = msr;
}
/* This can update new_msr and vector if AIL applies */
ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
powerpc_set_excp_state(cpu, vector, new_msr);
}
#else
static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
{
g_assert_not_reached();
}
#endif
/* /*
* Note that this function should be greatly optimized when called * Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt * with a constant excp, from ppc_hw_interrupt
@ -768,7 +1422,6 @@ static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
switch (excp_model) { switch (excp_model) {
case POWERPC_EXCP_602:
case POWERPC_EXCP_603: case POWERPC_EXCP_603:
case POWERPC_EXCP_G2: case POWERPC_EXCP_G2:
/* Swap temporary saved registers with GPRs */ /* Swap temporary saved registers with GPRs */
@ -872,6 +1525,19 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp)
CPUPPCState *env = &cpu->env; CPUPPCState *env = &cpu->env;
switch (env->excp_model) { switch (env->excp_model) {
case POWERPC_EXCP_40x:
powerpc_excp_40x(cpu, excp);
break;
case POWERPC_EXCP_74xx:
powerpc_excp_74xx(cpu, excp);
break;
case POWERPC_EXCP_970:
case POWERPC_EXCP_POWER7:
case POWERPC_EXCP_POWER8:
case POWERPC_EXCP_POWER9:
case POWERPC_EXCP_POWER10:
powerpc_excp_books(cpu, excp);
break;
default: default:
powerpc_excp_legacy(cpu, excp); powerpc_excp_legacy(cpu, excp);
} }
@ -1155,7 +1821,6 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
(env->spr[SPR_PSSCR] & PSSCR_EC); (env->spr[SPR_PSSCR] & PSSCR_EC);
} }
#endif /* defined(TARGET_PPC64) */ #endif /* defined(TARGET_PPC64) */
#endif /* CONFIG_TCG */
static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
{ {
@ -1164,6 +1829,10 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
/* MSR:POW cannot be set by any form of rfi */ /* MSR:POW cannot be set by any form of rfi */
msr &= ~(1ULL << MSR_POW); msr &= ~(1ULL << MSR_POW);
/* MSR:TGPR cannot be set by any form of rfi */
if (env->flags & POWERPC_FLAG_TGPR)
msr &= ~(1ULL << MSR_TGPR);
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
/* Switching to 32-bit ? Crop the nip */ /* Switching to 32-bit ? Crop the nip */
if (!msr_is_64bit(env, msr)) { if (!msr_is_64bit(env, msr)) {
@ -1188,7 +1857,6 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
check_tlb_flush(env, false); check_tlb_flush(env, false);
} }
#ifdef CONFIG_TCG
void helper_rfi(CPUPPCState *env) void helper_rfi(CPUPPCState *env)
{ {
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);

View File

@ -646,7 +646,6 @@ DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl) DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl) DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_1(msgsnd, void, tl)
DEF_HELPER_2(msgclr, void, env, tl) DEF_HELPER_2(msgclr, void, env, tl)
DEF_HELPER_1(book3s_msgsnd, void, tl) DEF_HELPER_1(book3s_msgsnd, void, tl)
@ -707,6 +706,7 @@ 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_pit, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_2(store_40x_pid, void, env, tl)
DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl)
DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl)

View File

@ -156,7 +156,8 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
*/ */
unsigned immu_idx, dmmu_idx; unsigned immu_idx, dmmu_idx;
dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1; dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1;
if (env->mmu_model & POWERPC_MMU_BOOKE) { if (env->mmu_model == POWERPC_MMU_BOOKE ||
env->mmu_model == POWERPC_MMU_BOOKE206) {
dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0; dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0;
immu_idx = dmmu_idx; immu_idx = dmmu_idx;
immu_idx |= msr & (1 << MSR_IS) ? 2 : 0; immu_idx |= msr & (1 << MSR_IS) ? 2 : 0;
@ -201,7 +202,11 @@ void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
void cpu_interrupt_exittb(CPUState *cs) void cpu_interrupt_exittb(CPUState *cs)
{ {
if (!kvm_enabled()) { /*
* We don't need to worry about translation blocks
* when running with KVM.
*/
if (kvm_enabled()) {
return; return;
} }
@ -233,7 +238,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
((value >> MSR_DR) & 1) != msr_dr) { ((value >> MSR_DR) & 1) != msr_dr) {
cpu_interrupt_exittb(cs); cpu_interrupt_exittb(cs);
} }
if ((env->mmu_model & POWERPC_MMU_BOOKE) && if ((env->mmu_model == POWERPC_MMU_BOOKE ||
env->mmu_model == POWERPC_MMU_BOOKE206) &&
((value >> MSR_GS) & 1) != msr_gs) { ((value >> MSR_GS) & 1) != msr_gs) {
cpu_interrupt_exittb(cs); cpu_interrupt_exittb(cs);
} }

View File

@ -488,27 +488,6 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
} }
} }
/*****************************************************************************/
/* 602 specific instructions */
/* mfrom is the most crazy instruction ever seen, imho ! */
/* Real implementation uses a ROM table. Do the same */
/*
* Extremely decomposed:
* -arg / 256
* return 256 * log10(10 + 1.0) + 0.5
*/
#if !defined(CONFIG_USER_ONLY)
target_ulong helper_602_mfrom(target_ulong arg)
{
if (likely(arg < 602)) {
#include "mfrom_table.c.inc"
return mfrom_ROM_table[arg];
} else {
return 0;
}
}
#endif
/*****************************************************************************/ /*****************************************************************************/
/* Altivec extension helpers */ /* Altivec extension helpers */
#if defined(HOST_WORDS_BIGENDIAN) #if defined(HOST_WORDS_BIGENDIAN)

View File

@ -1,78 +0,0 @@
static const uint8_t mfrom_ROM_table[602] = {
77, 77, 76, 76, 75, 75, 74, 74,
73, 73, 72, 72, 71, 71, 70, 70,
69, 69, 68, 68, 68, 67, 67, 66,
66, 65, 65, 64, 64, 64, 63, 63,
62, 62, 61, 61, 61, 60, 60, 59,
59, 58, 58, 58, 57, 57, 56, 56,
56, 55, 55, 54, 54, 54, 53, 53,
53, 52, 52, 51, 51, 51, 50, 50,
50, 49, 49, 49, 48, 48, 47, 47,
47, 46, 46, 46, 45, 45, 45, 44,
44, 44, 43, 43, 43, 42, 42, 42,
42, 41, 41, 41, 40, 40, 40, 39,
39, 39, 39, 38, 38, 38, 37, 37,
37, 37, 36, 36, 36, 35, 35, 35,
35, 34, 34, 34, 34, 33, 33, 33,
33, 32, 32, 32, 32, 31, 31, 31,
31, 30, 30, 30, 30, 29, 29, 29,
29, 28, 28, 28, 28, 28, 27, 27,
27, 27, 26, 26, 26, 26, 26, 25,
25, 25, 25, 25, 24, 24, 24, 24,
24, 23, 23, 23, 23, 23, 23, 22,
22, 22, 22, 22, 21, 21, 21, 21,
21, 21, 20, 20, 20, 20, 20, 20,
19, 19, 19, 19, 19, 19, 19, 18,
18, 18, 18, 18, 18, 17, 17, 17,
17, 17, 17, 17, 16, 16, 16, 16,
16, 16, 16, 16, 15, 15, 15, 15,
15, 15, 15, 15, 14, 14, 14, 14,
14, 14, 14, 14, 13, 13, 13, 13,
13, 13, 13, 13, 13, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 11,
11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 0,
};

View File

@ -1,34 +0,0 @@
#define _GNU_SOURCE
#include "qemu/osdep.h"
#include <math.h>
int main(void)
{
double d;
uint8_t n;
int i;
printf("static const uint8_t mfrom_ROM_table[602] =\n{\n ");
for (i = 0; i < 602; i++) {
/*
* Extremely decomposed:
* -T0 / 256
* T0 = 256 * log10(10 + 1.0) + 0.5
*/
d = -i;
d /= 256.0;
d = exp10(d);
d += 1.0;
d = log10(d);
d *= 256;
d += 0.5;
n = d;
printf("%3d, ", n);
if ((i & 7) == 7) {
printf("\n ");
}
}
printf("\n};\n");
return 0;
}

View File

@ -1367,22 +1367,34 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
case -2: case -2:
/* Access rights violation */ /* Access rights violation */
cs->exception_index = POWERPC_EXCP_ISI; cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000; if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->error_code = 0;
} else {
env->error_code = 0x08000000;
}
break; break;
case -3: case -3:
/* No execute protection violation */ /* No execute protection violation */
if ((env->mmu_model == POWERPC_MMU_BOOKE) || if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) { (env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->spr[SPR_BOOKE_ESR] = 0x00000000; env->spr[SPR_BOOKE_ESR] = 0x00000000;
env->error_code = 0;
} else {
env->error_code = 0x10000000;
} }
cs->exception_index = POWERPC_EXCP_ISI; cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
break; break;
case -4: case -4:
/* Direct store exception */ /* Direct store exception */
/* No code fetch is allowed in direct-store areas */ /* No code fetch is allowed in direct-store areas */
cs->exception_index = POWERPC_EXCP_ISI; cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000; if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->error_code = 0;
} else {
env->error_code = 0x10000000;
}
break; break;
} }
} else { } else {

View File

@ -664,6 +664,14 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
void helper_store_40x_pid(CPUPPCState *env, target_ulong val)
{
if (env->spr[SPR_40x_PID] != val) {
env->spr[SPR_40x_PID] = val;
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
}
}
target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry) target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
{ {
ppcemb_tlb_t *tlb; ppcemb_tlb_t *tlb;
@ -681,7 +689,7 @@ target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
size = PPC4XX_TLBHI_SIZE_DEFAULT; size = PPC4XX_TLBHI_SIZE_DEFAULT;
} }
ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
env->spr[SPR_40x_PID] = tlb->PID; helper_store_40x_pid(env, tlb->PID);
return ret; return ret;
} }
@ -794,6 +802,8 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
tlb->prot & PAGE_WRITE ? 'w' : '-', tlb->prot & PAGE_WRITE ? 'w' : '-',
tlb->prot & PAGE_EXEC ? 'x' : '-', tlb->prot & PAGE_EXEC ? 'x' : '-',
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
} }
target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address) target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)

View File

@ -894,7 +894,7 @@ void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn)
{ {
TCGv t0 = tcg_temp_new(); TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF); tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF);
gen_store_spr(SPR_40x_PID, t0); gen_helper_store_40x_pid(cpu_env, t0);
tcg_temp_free(t0); tcg_temp_free(t0);
} }
@ -6272,33 +6272,6 @@ static void gen_srq(DisasContext *ctx)
} }
} }
/* PowerPC 602 specific instructions */
/* dsa */
static void gen_dsa(DisasContext *ctx)
{
/* XXX: TODO */
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
}
/* esa */
static void gen_esa(DisasContext *ctx)
{
/* XXX: TODO */
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
}
/* mfrom */
static void gen_mfrom(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
GEN_PRIV;
#else
CHK_SV;
gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
#endif /* defined(CONFIG_USER_ONLY) */
}
/* 602 - 603 - G2 TLB management */ /* 602 - 603 - G2 TLB management */
/* tlbld */ /* tlbld */
@ -7779,9 +7752,6 @@ GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR),
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 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(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR), GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC),
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC),
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC),
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB), 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_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER), GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),