mirror of https://github.com/xqemu/xqemu.git
ppc patch queue 2016-11-15
Latest set of ppc and spapr related patches. Highlights are: * More POWER9 instructions * Fix some subtle outstanding bugs * Add some extra tests One patch affects bitops.h, so isn't strictly ppc related. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJYKncYAAoJEGw4ysog2bOSgtQP/3qE+/3ITaCwDtXaRtNKGXUM wRM+d6ZplpSz+tKPAxbvaKJKJ38WiuGSO8BZ1IGu6ZtYE7frjDoK3aqXehvlHmjz k5mgfMSoAzUj6Yj1Wk1OAXQrRb46crzqk1uD6bjVa9Ctrx1ODxfekB3wv5cnaQWM r4mfwyr3mG5und70eUZ/KPO1vsnDvQV5npcu757pRmO+vW3qkiKhu5bbZXQkpSk+ 8sMNUjn6M+uZqNlFMy3ummru08GAMuvqlkVA4o1hcTMRdLaOs5Kddev8yauj3bs/ LvX0JGu+ucXhHsxvbmG13OEax9u6yPPTBk3DcjxSZbLNUvDpuWV1I15+QIAn9OrY zjUfOGzbKRbyVlM1vPNkn3hW88Y1OPfegOk3PEyJqdgUcdtsPnB64BRJpkxF54OT h5FGjadNZpeZZkzOT14XJmxN94lSizm5H0Fp3kCJVjbsEYGhj53DnW2iusGUXCpY 51WG3PCpFzyhHotFkj1sIj6IK0vUmHi0wtlAPy2iMtFSJnEVEfm/WmL5t6szyOfU FxaijuqoQu8/D71pdyNn0XVEP2HMXo4oo832e/7MwJCtg/dBu4j1VKb4K7p/bgJ8 w/9vv1510JV6x2R9rryB6UZHv6bflgtJXRedtORs01hh9S2mP6BUcGa5T/0uI7vk 1y2lVx2InmjgrJXnOtVR =nEJM -----END PGP SIGNATURE----- Merge remote-tracking branch 'dgibson/tags/ppc-for-2.8-20161115' into staging ppc patch queue 2016-11-15 Latest set of ppc and spapr related patches. Highlights are: * More POWER9 instructions * Fix some subtle outstanding bugs * Add some extra tests One patch affects bitops.h, so isn't strictly ppc related. # gpg: Signature made Tue 15 Nov 2016 02:46:48 AM GMT # gpg: using RSA key 0x6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * dgibson/tags/ppc-for-2.8-20161115: boot-serial-test: Add a test for the powernv machine tests: add XSCOM tests for the PowerNV machine ppc/pnv: Fix fatal bug on 32-bit hosts ppc/pnv: fix xscom address translation for POWER9 ppc/pnv: add a 'xscom_core_base' field to PnvChipClass spapr-vty: Fix bad assert() statement FU exceptions should carry a cause (IC) spapr: Fix migration of PCI host bridges from qemu-2.7 target-ppc: Implement bcdctz. instruction target-ppc: Implement bcdcfz. instruction target-ppc: Implement bcdctn. instruction target-ppc: Implement bcdcfn. instruction ppc: Remove some stub POWER6 models ppc/pnv: fix compile breakage on old gcc powernv: CPU compatibility modes don't make sense for powernv target-ppc: add vprtyb[w/d/q] instructions target-ppc: add vrldnm and vrlwnm instructions target-ppc: add vrldnmi and vrlwmi instructions bitops: fix rol/ror when shift is zero Message-id: 1479178144-28153-1-git-send-email-david@gibson.dropbear.id.au Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
8a7b5c1893
|
@ -2286,6 +2286,10 @@ const struct powerpc_opcode powerpc_opcodes[] = {
|
|||
{ "vrlh", VX(4, 68), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
{ "vrlw", VX(4, 132), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
{ "vrsqrtefp", VX(4, 330), VX_MASK, PPCVEC, { VD, VB } },
|
||||
{ "vrldmi", VX(4, 197), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
{ "vrldnm", VX(4, 453), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
{ "vrlwmi", VX(4, 133), VX_MASK, PPCVEC, { VD, VA, VB} },
|
||||
{ "vrlwnm", VX(4, 389), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
{ "vsel", VXA(4, 42), VXA_MASK, PPCVEC, { VD, VA, VB, VC } },
|
||||
{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
{ "vslb", VX(4, 260), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
|
@ -37,7 +38,15 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
|
|||
qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
|
||||
}
|
||||
for (i = 0; i < size; i++) {
|
||||
assert((dev->in - dev->out) < VTERM_BUFSIZE);
|
||||
if (dev->in - dev->out >= VTERM_BUFSIZE) {
|
||||
static bool reported;
|
||||
if (!reported) {
|
||||
error_report("VTY input buffer exhausted - characters dropped."
|
||||
" (input size = %i)", size);
|
||||
reported = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
|
||||
}
|
||||
}
|
||||
|
|
16
hw/ppc/pnv.c
16
hw/ppc/pnv.c
|
@ -110,7 +110,7 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
|
|||
CPUState *cs = CPU(DEVICE(pc->threads));
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
int smt_threads = ppc_get_compat_smt_threads(cpu);
|
||||
int smt_threads = CPU_CORE(pc)->nr_threads;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||
uint32_t servers_prop[smt_threads];
|
||||
|
@ -206,10 +206,6 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
|
|||
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||
pa_features, sizeof(pa_features))));
|
||||
|
||||
if (cpu->cpu_version) {
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
|
||||
}
|
||||
|
||||
/* Build interrupt servers properties */
|
||||
for (i = 0; i < smt_threads; i++) {
|
||||
servers_prop[i] = cpu_to_be32(pc->pir + i);
|
||||
|
@ -525,6 +521,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
|
|||
k->cores_mask = POWER8E_CORE_MASK;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->xscom_base = 0x003fc0000000000ull;
|
||||
k->xscom_core_base = 0x10000000ull;
|
||||
dc->desc = "PowerNV Chip POWER8E";
|
||||
}
|
||||
|
||||
|
@ -546,6 +543,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
|
|||
k->cores_mask = POWER8_CORE_MASK;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->xscom_base = 0x003fc0000000000ull;
|
||||
k->xscom_core_base = 0x10000000ull;
|
||||
dc->desc = "PowerNV Chip POWER8";
|
||||
}
|
||||
|
||||
|
@ -567,6 +565,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
|
|||
k->cores_mask = POWER8_CORE_MASK;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->xscom_base = 0x003fc0000000000ull;
|
||||
k->xscom_core_base = 0x10000000ull;
|
||||
dc->desc = "PowerNV Chip POWER8NVL";
|
||||
}
|
||||
|
||||
|
@ -588,6 +587,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
|
|||
k->cores_mask = POWER9_CORE_MASK;
|
||||
k->core_pir = pnv_chip_core_pir_p9;
|
||||
k->xscom_base = 0x00603fc00000000ull;
|
||||
k->xscom_core_base = 0x0ull;
|
||||
dc->desc = "PowerNV Chip POWER9";
|
||||
}
|
||||
|
||||
|
@ -620,7 +620,7 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
|
|||
chip->cores_mask &= pcc->cores_mask;
|
||||
|
||||
/* now that we have a sane layout, let check the number of cores */
|
||||
cores_max = hweight_long(chip->cores_mask);
|
||||
cores_max = ctpop64(chip->cores_mask);
|
||||
if (chip->nr_cores > cores_max) {
|
||||
error_setg(errp, "warning: too many cores for chip ! Limit is %d",
|
||||
cores_max);
|
||||
|
@ -695,7 +695,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
|
|||
object_unref(OBJECT(pnv_core));
|
||||
|
||||
/* Each core has an XSCOM MMIO region */
|
||||
pnv_xscom_add_subregion(chip, PNV_XSCOM_EX_CORE_BASE(core_hwid),
|
||||
pnv_xscom_add_subregion(chip,
|
||||
PNV_XSCOM_EX_CORE_BASE(pcc->xscom_core_base,
|
||||
core_hwid),
|
||||
&PNV_CORE(pnv_core)->xscom_regs);
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "hw/ppc/ppc.h"
|
||||
#include "hw/ppc/pnv.h"
|
||||
#include "hw/ppc/pnv_core.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
|
||||
static void powernv_cpu_reset(void *opaque)
|
||||
{
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#include "hw/ppc/pnv_lpc.h"
|
||||
#include "hw/ppc/pnv.h"
|
||||
#include "hw/ppc/pnv_lpc.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
#include "hw/ppc/fdt.h"
|
||||
|
||||
#include <libfdt.h>
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include "hw/sysbus.h"
|
||||
|
||||
#include "hw/ppc/fdt.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
#include "hw/ppc/pnv.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
|
@ -124,8 +124,8 @@ static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
|
|||
goto complete;
|
||||
}
|
||||
|
||||
val = address_space_ldq(&chip->xscom_as, pcba << 3, MEMTXATTRS_UNSPECIFIED,
|
||||
&result);
|
||||
val = address_space_ldq(&chip->xscom_as, (uint64_t) pcba << 3,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XSCOM read failed at @0x%"
|
||||
HWADDR_PRIx " pcba=0x%08x\n", addr, pcba);
|
||||
|
@ -150,8 +150,8 @@ static void xscom_write(void *opaque, hwaddr addr, uint64_t val,
|
|||
goto complete;
|
||||
}
|
||||
|
||||
address_space_stq(&chip->xscom_as, pcba << 3, val, MEMTXATTRS_UNSPECIFIED,
|
||||
&result);
|
||||
address_space_stq(&chip->xscom_as, (uint64_t) pcba << 3, val,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
if (result != MEMTX_OK) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XSCOM write failed at @0x%"
|
||||
HWADDR_PRIx " pcba=0x%08x data=0x%" PRIx64 "\n",
|
||||
|
|
|
@ -1658,19 +1658,25 @@ static int spapr_pci_post_load(void *opaque, int version_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool version_before_3(void *opaque, int version_id)
|
||||
{
|
||||
return version_id < 3;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_spapr_pci = {
|
||||
.name = "spapr_pci",
|
||||
.version_id = 2,
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 2,
|
||||
.pre_save = spapr_pci_pre_save,
|
||||
.post_load = spapr_pci_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
|
||||
VMSTATE_UINT32_EQUAL(dma_liobn[0], sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(mem_win_addr, sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
|
||||
VMSTATE_UNUSED_TEST(version_before_3,
|
||||
sizeof(uint32_t) /* dma_liobn[0] */
|
||||
+ sizeof(uint64_t) /* mem_win_addr */
|
||||
+ sizeof(uint64_t) /* mem_win_size */
|
||||
+ sizeof(uint64_t) /* io_win_addr */
|
||||
+ sizeof(uint64_t) /* io_win_size */),
|
||||
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
|
||||
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
|
||||
VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ppc/pnv_xscom.h"
|
||||
#include "hw/ppc/pnv_lpc.h"
|
||||
|
||||
#define TYPE_PNV_CHIP "powernv-chip"
|
||||
|
@ -70,6 +69,7 @@ typedef struct PnvChipClass {
|
|||
uint64_t cores_mask;
|
||||
|
||||
hwaddr xscom_base;
|
||||
hwaddr xscom_core_base;
|
||||
|
||||
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
|
||||
} PnvChipClass;
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "qom/object.h"
|
||||
|
||||
typedef struct PnvChip PnvChip;
|
||||
|
||||
typedef struct PnvXScomInterface {
|
||||
Object parent;
|
||||
} PnvXScomInterface;
|
||||
|
@ -42,7 +40,7 @@ typedef struct PnvXScomInterfaceClass {
|
|||
} PnvXScomInterfaceClass;
|
||||
|
||||
/*
|
||||
* Layout of the XSCOM PCB addresses of EX core 1
|
||||
* Layout of the XSCOM PCB addresses of EX core 1 (POWER 8)
|
||||
*
|
||||
* GPIO 0x1100xxxx
|
||||
* SCOM 0x1101xxxx
|
||||
|
@ -56,8 +54,7 @@ typedef struct PnvXScomInterfaceClass {
|
|||
* PCB SLAVE 0x110Fxxxx
|
||||
*/
|
||||
|
||||
#define PNV_XSCOM_EX_BASE 0x10000000
|
||||
#define PNV_XSCOM_EX_CORE_BASE(i) (PNV_XSCOM_EX_BASE | (((uint64_t)i) << 24))
|
||||
#define PNV_XSCOM_EX_CORE_BASE(base, i) (base | (((uint64_t)i) << 24))
|
||||
#define PNV_XSCOM_EX_CORE_SIZE 0x100000
|
||||
|
||||
#define PNV_XSCOM_LPC_BASE 0xb0020
|
||||
|
|
|
@ -218,7 +218,7 @@ static inline unsigned long hweight_long(unsigned long w)
|
|||
*/
|
||||
static inline uint8_t rol8(uint8_t word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> (8 - shift));
|
||||
return (word << shift) | (word >> ((8 - shift) & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,7 +228,7 @@ static inline uint8_t rol8(uint8_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint8_t ror8(uint8_t word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (8 - shift));
|
||||
return (word >> shift) | (word << ((8 - shift) & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,7 +238,7 @@ static inline uint8_t ror8(uint8_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint16_t rol16(uint16_t word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> (16 - shift));
|
||||
return (word << shift) | (word >> ((16 - shift) & 15));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -248,7 +248,7 @@ static inline uint16_t rol16(uint16_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint16_t ror16(uint16_t word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (16 - shift));
|
||||
return (word >> shift) | (word << ((16 - shift) & 15));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +258,7 @@ static inline uint16_t ror16(uint16_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint32_t rol32(uint32_t word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> (32 - shift));
|
||||
return (word << shift) | (word >> ((32 - shift) & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,7 +268,7 @@ static inline uint32_t rol32(uint32_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint32_t ror32(uint32_t word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (32 - shift));
|
||||
return (word >> shift) | (word << ((32 - shift) & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,7 +278,7 @@ static inline uint32_t ror32(uint32_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint64_t rol64(uint64_t word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> (64 - shift));
|
||||
return (word << shift) | (word >> ((64 - shift) & 63));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,7 +288,7 @@ static inline uint64_t rol64(uint64_t word, unsigned int shift)
|
|||
*/
|
||||
static inline uint64_t ror64(uint64_t word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (64 - shift));
|
||||
return (word >> shift) | (word << ((64 - shift) & 63));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1130,10 +1130,6 @@
|
|||
#if defined(TODO)
|
||||
POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6,
|
||||
"POWER6")
|
||||
POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5,
|
||||
"POWER6 running in POWER5 mode")
|
||||
POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6,
|
||||
"POWER6A")
|
||||
#endif
|
||||
POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7,
|
||||
"POWER7 v2.3")
|
||||
|
|
|
@ -549,8 +549,6 @@ enum {
|
|||
CPU_POWERPC_POWER5 = 0x003A0203,
|
||||
CPU_POWERPC_POWER5P_v21 = 0x003B0201,
|
||||
CPU_POWERPC_POWER6 = 0x003E0000,
|
||||
CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */
|
||||
CPU_POWERPC_POWER6A = 0x0F000002,
|
||||
CPU_POWERPC_POWER_SERVER_MASK = 0xFFFF0000,
|
||||
CPU_POWERPC_POWER7_BASE = 0x003F0000,
|
||||
CPU_POWERPC_POWER7_v23 = 0x003F0203,
|
||||
|
|
|
@ -427,6 +427,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
|
||||
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
|
||||
case POWERPC_EXCP_FU: /* Facility unavailable exception */
|
||||
#ifdef TARGET_PPC64
|
||||
env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
|
||||
#endif
|
||||
break;
|
||||
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
||||
LOG_EXCP("PIT exception\n");
|
||||
|
|
|
@ -223,6 +223,9 @@ DEF_HELPER_3(vsro, void, avr, avr, avr)
|
|||
DEF_HELPER_3(vsrv, void, avr, avr, avr)
|
||||
DEF_HELPER_3(vslv, void, avr, avr, avr)
|
||||
DEF_HELPER_3(vaddcuw, void, avr, avr, avr)
|
||||
DEF_HELPER_2(vprtybw, void, avr, avr)
|
||||
DEF_HELPER_2(vprtybd, void, avr, avr)
|
||||
DEF_HELPER_2(vprtybq, void, avr, avr)
|
||||
DEF_HELPER_3(vsubcuw, void, avr, avr, avr)
|
||||
DEF_HELPER_2(lvsl, void, avr, tl)
|
||||
DEF_HELPER_2(lvsr, void, avr, tl)
|
||||
|
@ -325,6 +328,10 @@ DEF_HELPER_4(vmaxfp, void, env, avr, avr, avr)
|
|||
DEF_HELPER_4(vminfp, void, env, avr, avr, avr)
|
||||
DEF_HELPER_3(vrefp, void, env, avr, avr)
|
||||
DEF_HELPER_3(vrsqrtefp, void, env, avr, avr)
|
||||
DEF_HELPER_3(vrlwmi, void, avr, avr, avr)
|
||||
DEF_HELPER_3(vrldmi, void, avr, avr, avr)
|
||||
DEF_HELPER_3(vrldnm, void, avr, avr, avr)
|
||||
DEF_HELPER_3(vrlwnm, void, avr, avr, avr)
|
||||
DEF_HELPER_5(vmaddfp, void, env, avr, avr, avr, avr)
|
||||
DEF_HELPER_5(vnmsubfp, void, env, avr, avr, avr, avr)
|
||||
DEF_HELPER_3(vexptefp, void, env, avr, avr)
|
||||
|
@ -371,6 +378,10 @@ DEF_HELPER_4(vpermxor, void, avr, avr, avr, avr)
|
|||
|
||||
DEF_HELPER_4(bcdadd, i32, avr, avr, avr, i32)
|
||||
DEF_HELPER_4(bcdsub, i32, avr, avr, avr, i32)
|
||||
DEF_HELPER_3(bcdcfn, i32, avr, avr, i32)
|
||||
DEF_HELPER_3(bcdctn, i32, avr, avr, i32)
|
||||
DEF_HELPER_3(bcdcfz, i32, avr, avr, i32)
|
||||
DEF_HELPER_3(bcdctz, i32, avr, avr, i32)
|
||||
|
||||
DEF_HELPER_2(xsadddp, void, env, i32)
|
||||
DEF_HELPER_2(xssubdp, void, env, i32)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "internal.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
@ -527,6 +528,40 @@ void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
|||
}
|
||||
}
|
||||
|
||||
/* vprtybw */
|
||||
void helper_vprtybw(ppc_avr_t *r, ppc_avr_t *b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
|
||||
uint64_t res = b->u32[i] ^ (b->u32[i] >> 16);
|
||||
res ^= res >> 8;
|
||||
r->u32[i] = res & 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* vprtybd */
|
||||
void helper_vprtybd(ppc_avr_t *r, ppc_avr_t *b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
|
||||
uint64_t res = b->u64[i] ^ (b->u64[i] >> 32);
|
||||
res ^= res >> 16;
|
||||
res ^= res >> 8;
|
||||
r->u64[i] = res & 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* vprtybq */
|
||||
void helper_vprtybq(ppc_avr_t *r, ppc_avr_t *b)
|
||||
{
|
||||
uint64_t res = b->u64[0] ^ b->u64[1];
|
||||
res ^= res >> 32;
|
||||
res ^= res >> 16;
|
||||
res ^= res >> 8;
|
||||
r->u64[LO_IDX] = res & 1;
|
||||
r->u64[HI_IDX] = 0;
|
||||
}
|
||||
|
||||
#define VARITH_DO(name, op, element) \
|
||||
void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
|
||||
{ \
|
||||
|
@ -1717,6 +1752,34 @@ void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
|
|||
}
|
||||
}
|
||||
|
||||
#define VRLMI(name, size, element, insert) \
|
||||
void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
|
||||
uint##size##_t src1 = a->element[i]; \
|
||||
uint##size##_t src2 = b->element[i]; \
|
||||
uint##size##_t src3 = r->element[i]; \
|
||||
uint##size##_t begin, end, shift, mask, rot_val; \
|
||||
\
|
||||
shift = extract##size(src2, 0, 6); \
|
||||
end = extract##size(src2, 8, 6); \
|
||||
begin = extract##size(src2, 16, 6); \
|
||||
rot_val = rol##size(src1, shift); \
|
||||
mask = mask_u##size(begin, end); \
|
||||
if (insert) { \
|
||||
r->element[i] = (rot_val & mask) | (src3 & ~mask); \
|
||||
} else { \
|
||||
r->element[i] = (rot_val & mask); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
VRLMI(vrldmi, 64, u64, 1);
|
||||
VRLMI(vrlwmi, 32, u32, 1);
|
||||
VRLMI(vrldnm, 64, u64, 0);
|
||||
VRLMI(vrlwnm, 32, u32, 0);
|
||||
|
||||
void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
|
||||
ppc_avr_t *c)
|
||||
{
|
||||
|
@ -2429,6 +2492,8 @@ void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
|
|||
#define BCD_NEG_PREF 0xD
|
||||
#define BCD_NEG_ALT 0xB
|
||||
#define BCD_PLUS_ALT_2 0xE
|
||||
#define NATIONAL_PLUS 0x2B
|
||||
#define NATIONAL_NEG 0x2D
|
||||
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
#define BCD_DIG_BYTE(n) (15 - (n/2))
|
||||
|
@ -2495,6 +2560,33 @@ static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
|
|||
}
|
||||
}
|
||||
|
||||
static int bcd_cmp_zero(ppc_avr_t *bcd)
|
||||
{
|
||||
if (bcd->u64[HI_IDX] == 0 && (bcd->u64[LO_IDX] >> 4) == 0) {
|
||||
return 1 << CRF_EQ;
|
||||
} else {
|
||||
return (bcd_get_sgn(bcd) == 1) ? 1 << CRF_GT : 1 << CRF_LT;
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t get_national_digit(ppc_avr_t *reg, int n)
|
||||
{
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
return reg->u16[8 - n];
|
||||
#else
|
||||
return reg->u16[n];
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_national_digit(ppc_avr_t *reg, uint8_t val, int n)
|
||||
{
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
reg->u16[8 - n] = val;
|
||||
#else
|
||||
reg->u16[n] = val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
|
||||
{
|
||||
int i;
|
||||
|
@ -2625,6 +2717,163 @@ uint32_t helper_bcdsub(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
|
|||
return helper_bcdadd(r, a, &bcopy, ps);
|
||||
}
|
||||
|
||||
uint32_t helper_bcdcfn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
|
||||
{
|
||||
int i;
|
||||
int cr = 0;
|
||||
uint16_t national = 0;
|
||||
uint16_t sgnb = get_national_digit(b, 0);
|
||||
ppc_avr_t ret = { .u64 = { 0, 0 } };
|
||||
int invalid = (sgnb != NATIONAL_PLUS && sgnb != NATIONAL_NEG);
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
national = get_national_digit(b, i);
|
||||
if (unlikely(national < 0x30 || national > 0x39)) {
|
||||
invalid = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
bcd_put_digit(&ret, national & 0xf, i);
|
||||
}
|
||||
|
||||
if (sgnb == NATIONAL_PLUS) {
|
||||
bcd_put_digit(&ret, (ps == 0) ? BCD_PLUS_PREF_1 : BCD_PLUS_PREF_2, 0);
|
||||
} else {
|
||||
bcd_put_digit(&ret, BCD_NEG_PREF, 0);
|
||||
}
|
||||
|
||||
cr = bcd_cmp_zero(&ret);
|
||||
|
||||
if (unlikely(invalid)) {
|
||||
cr = 1 << CRF_SO;
|
||||
}
|
||||
|
||||
*r = ret;
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
uint32_t helper_bcdctn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
|
||||
{
|
||||
int i;
|
||||
int cr = 0;
|
||||
int sgnb = bcd_get_sgn(b);
|
||||
int invalid = (sgnb == 0);
|
||||
ppc_avr_t ret = { .u64 = { 0, 0 } };
|
||||
|
||||
int ox_flag = (b->u64[HI_IDX] != 0) || ((b->u64[LO_IDX] >> 32) != 0);
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
set_national_digit(&ret, 0x30 + bcd_get_digit(b, i, &invalid), i);
|
||||
|
||||
if (unlikely(invalid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_national_digit(&ret, (sgnb == -1) ? NATIONAL_NEG : NATIONAL_PLUS, 0);
|
||||
|
||||
cr = bcd_cmp_zero(b);
|
||||
|
||||
if (ox_flag) {
|
||||
cr |= 1 << CRF_SO;
|
||||
}
|
||||
|
||||
if (unlikely(invalid)) {
|
||||
cr = 1 << CRF_SO;
|
||||
}
|
||||
|
||||
*r = ret;
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
|
||||
{
|
||||
int i;
|
||||
int cr = 0;
|
||||
int invalid = 0;
|
||||
int zone_digit = 0;
|
||||
int zone_lead = ps ? 0xF : 0x3;
|
||||
int digit = 0;
|
||||
ppc_avr_t ret = { .u64 = { 0, 0 } };
|
||||
int sgnb = b->u8[BCD_DIG_BYTE(0)] >> 4;
|
||||
|
||||
if (unlikely((sgnb < 0xA) && ps)) {
|
||||
invalid = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
zone_digit = (i * 2) ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead;
|
||||
digit = b->u8[BCD_DIG_BYTE(i * 2)] & 0xF;
|
||||
if (unlikely(zone_digit != zone_lead || digit > 0x9)) {
|
||||
invalid = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
bcd_put_digit(&ret, digit, i + 1);
|
||||
}
|
||||
|
||||
if ((ps && (sgnb == 0xB || sgnb == 0xD)) ||
|
||||
(!ps && (sgnb & 0x4))) {
|
||||
bcd_put_digit(&ret, BCD_NEG_PREF, 0);
|
||||
} else {
|
||||
bcd_put_digit(&ret, BCD_PLUS_PREF_1, 0);
|
||||
}
|
||||
|
||||
cr = bcd_cmp_zero(&ret);
|
||||
|
||||
if (unlikely(invalid)) {
|
||||
cr = 1 << CRF_SO;
|
||||
}
|
||||
|
||||
*r = ret;
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
|
||||
{
|
||||
int i;
|
||||
int cr = 0;
|
||||
uint8_t digit = 0;
|
||||
int sgnb = bcd_get_sgn(b);
|
||||
int zone_lead = (ps) ? 0xF0 : 0x30;
|
||||
int invalid = (sgnb == 0);
|
||||
ppc_avr_t ret = { .u64 = { 0, 0 } };
|
||||
|
||||
int ox_flag = ((b->u64[HI_IDX] >> 4) != 0);
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
digit = bcd_get_digit(b, i + 1, &invalid);
|
||||
|
||||
if (unlikely(invalid)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret.u8[BCD_DIG_BYTE(i * 2)] = zone_lead + digit;
|
||||
}
|
||||
|
||||
if (ps) {
|
||||
bcd_put_digit(&ret, (sgnb == 1) ? 0xC : 0xD, 1);
|
||||
} else {
|
||||
bcd_put_digit(&ret, (sgnb == 1) ? 0x3 : 0x7, 1);
|
||||
}
|
||||
|
||||
cr = bcd_cmp_zero(b);
|
||||
|
||||
if (ox_flag) {
|
||||
cr |= 1 << CRF_SO;
|
||||
}
|
||||
|
||||
if (unlikely(invalid)) {
|
||||
cr = 1 << CRF_SO;
|
||||
}
|
||||
|
||||
*r = ret;
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* PowerPC interal definitions for qemu.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PPC_INTERNAL_H
|
||||
#define PPC_INTERNAL_H
|
||||
|
||||
#define FUNC_MASK(name, ret_type, size, max_val) \
|
||||
static inline ret_type name(uint##size##_t start, \
|
||||
uint##size##_t end) \
|
||||
{ \
|
||||
ret_type ret, max_bit = size - 1; \
|
||||
\
|
||||
if (likely(start == 0)) { \
|
||||
ret = max_val << (max_bit - end); \
|
||||
} else if (likely(end == max_bit)) { \
|
||||
ret = max_val >> start; \
|
||||
} else { \
|
||||
ret = (((uint##size##_t)(-1ULL)) >> (start)) ^ \
|
||||
(((uint##size##_t)(-1ULL) >> (end)) >> 1); \
|
||||
if (unlikely(start > end)) { \
|
||||
return ~ret; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
FUNC_MASK(MASK, target_ulong, 64, UINT64_MAX);
|
||||
#else
|
||||
FUNC_MASK(MASK, target_ulong, 32, UINT32_MAX);
|
||||
#endif
|
||||
FUNC_MASK(mask_u32, uint32_t, 32, UINT32_MAX);
|
||||
FUNC_MASK(mask_u64, uint64_t, 64, UINT64_MAX);
|
||||
|
||||
#endif /* PPC_INTERNAL_H */
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "internal.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg-op.h"
|
||||
|
@ -561,34 +562,6 @@ EXTRACT_HELPER(DCM, 10, 6)
|
|||
/* DFP Z23-form */
|
||||
EXTRACT_HELPER(RMC, 9, 2)
|
||||
|
||||
/* Create a mask between <start> and <end> bits */
|
||||
static inline target_ulong MASK(uint32_t start, uint32_t end)
|
||||
{
|
||||
target_ulong ret;
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
if (likely(start == 0)) {
|
||||
ret = UINT64_MAX << (63 - end);
|
||||
} else if (likely(end == 63)) {
|
||||
ret = UINT64_MAX >> start;
|
||||
}
|
||||
#else
|
||||
if (likely(start == 0)) {
|
||||
ret = UINT32_MAX << (31 - end);
|
||||
} else if (likely(end == 31)) {
|
||||
ret = UINT32_MAX >> start;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
ret = (((target_ulong)(-1ULL)) >> (start)) ^
|
||||
(((target_ulong)(-1ULL) >> (end)) >> 1);
|
||||
if (unlikely(start > end))
|
||||
return ~ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXTRACT_HELPER_SPLIT(xT, 0, 1, 21, 5);
|
||||
EXTRACT_HELPER_SPLIT(xS, 0, 1, 21, 5);
|
||||
EXTRACT_HELPER_SPLIT(xA, 2, 1, 16, 5);
|
||||
|
|
|
@ -442,6 +442,9 @@ GEN_VXFORM(vmulesw, 4, 14);
|
|||
GEN_VXFORM(vslb, 2, 4);
|
||||
GEN_VXFORM(vslh, 2, 5);
|
||||
GEN_VXFORM(vslw, 2, 6);
|
||||
GEN_VXFORM(vrlwnm, 2, 6);
|
||||
GEN_VXFORM_DUAL(vslw, PPC_ALTIVEC, PPC_NONE, \
|
||||
vrlwnm, PPC_NONE, PPC2_ISA300)
|
||||
GEN_VXFORM(vsld, 2, 23);
|
||||
GEN_VXFORM(vsrb, 2, 8);
|
||||
GEN_VXFORM(vsrh, 2, 9);
|
||||
|
@ -488,8 +491,17 @@ GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
|
|||
GEN_VXFORM(vrlb, 2, 0);
|
||||
GEN_VXFORM(vrlh, 2, 1);
|
||||
GEN_VXFORM(vrlw, 2, 2);
|
||||
GEN_VXFORM(vrlwmi, 2, 2);
|
||||
GEN_VXFORM_DUAL(vrlw, PPC_ALTIVEC, PPC_NONE, \
|
||||
vrlwmi, PPC_NONE, PPC2_ISA300)
|
||||
GEN_VXFORM(vrld, 2, 3);
|
||||
GEN_VXFORM(vrldmi, 2, 3);
|
||||
GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \
|
||||
vrldmi, PPC_NONE, PPC2_ISA300)
|
||||
GEN_VXFORM(vsl, 2, 7);
|
||||
GEN_VXFORM(vrldnm, 2, 7);
|
||||
GEN_VXFORM_DUAL(vsl, PPC_ALTIVEC, PPC_NONE, \
|
||||
vrldnm, PPC_NONE, PPC2_ISA300)
|
||||
GEN_VXFORM(vsr, 2, 11);
|
||||
GEN_VXFORM_ENV(vpkuhum, 7, 0);
|
||||
GEN_VXFORM_ENV(vpkuwum, 7, 1);
|
||||
|
@ -693,6 +705,9 @@ GEN_VXFORM_NOA_ENV(vrfim, 5, 11);
|
|||
GEN_VXFORM_NOA_ENV(vrfin, 5, 8);
|
||||
GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
|
||||
GEN_VXFORM_NOA_ENV(vrfiz, 5, 9);
|
||||
GEN_VXFORM_NOA(vprtybw, 1, 24);
|
||||
GEN_VXFORM_NOA(vprtybd, 1, 24);
|
||||
GEN_VXFORM_NOA(vprtybq, 1, 24);
|
||||
|
||||
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
|
||||
static void glue(gen_, name)(DisasContext *ctx) \
|
||||
|
@ -945,8 +960,79 @@ static void gen_##op(DisasContext *ctx) \
|
|||
tcg_temp_free_i32(ps); \
|
||||
}
|
||||
|
||||
#define GEN_BCD2(op) \
|
||||
static void gen_##op(DisasContext *ctx) \
|
||||
{ \
|
||||
TCGv_ptr rd, rb; \
|
||||
TCGv_i32 ps; \
|
||||
\
|
||||
if (unlikely(!ctx->altivec_enabled)) { \
|
||||
gen_exception(ctx, POWERPC_EXCP_VPU); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
rb = gen_avr_ptr(rB(ctx->opcode)); \
|
||||
rd = gen_avr_ptr(rD(ctx->opcode)); \
|
||||
\
|
||||
ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \
|
||||
\
|
||||
gen_helper_##op(cpu_crf[6], rd, rb, ps); \
|
||||
\
|
||||
tcg_temp_free_ptr(rb); \
|
||||
tcg_temp_free_ptr(rd); \
|
||||
tcg_temp_free_i32(ps); \
|
||||
}
|
||||
|
||||
GEN_BCD(bcdadd)
|
||||
GEN_BCD(bcdsub)
|
||||
GEN_BCD2(bcdcfn)
|
||||
GEN_BCD2(bcdctn)
|
||||
GEN_BCD2(bcdcfz)
|
||||
GEN_BCD2(bcdctz)
|
||||
|
||||
static void gen_xpnd04_1(DisasContext *ctx)
|
||||
{
|
||||
switch (opc4(ctx->opcode)) {
|
||||
case 4:
|
||||
gen_bcdctz(ctx);
|
||||
break;
|
||||
case 5:
|
||||
gen_bcdctn(ctx);
|
||||
break;
|
||||
case 6:
|
||||
gen_bcdcfz(ctx);
|
||||
break;
|
||||
case 7:
|
||||
gen_bcdcfn(ctx);
|
||||
break;
|
||||
default:
|
||||
gen_invalid(ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_xpnd04_2(DisasContext *ctx)
|
||||
{
|
||||
switch (opc4(ctx->opcode)) {
|
||||
case 4:
|
||||
gen_bcdctz(ctx);
|
||||
break;
|
||||
case 6:
|
||||
gen_bcdcfz(ctx);
|
||||
break;
|
||||
case 7:
|
||||
gen_bcdcfn(ctx);
|
||||
break;
|
||||
default:
|
||||
gen_invalid(ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GEN_VXFORM_DUAL(vsubcuw, PPC_ALTIVEC, PPC_NONE, \
|
||||
xpnd04_1, PPC_NONE, PPC2_ISA300)
|
||||
GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \
|
||||
xpnd04_2, PPC_NONE, PPC2_ISA300)
|
||||
|
||||
GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
|
||||
bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
|
||||
|
@ -1023,3 +1109,5 @@ GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE,
|
|||
#undef GEN_VXFORM_NOA
|
||||
#undef GEN_VXFORM_UIMM
|
||||
#undef GEN_VAFORM_PAIRED
|
||||
|
||||
#undef GEN_BCD2
|
||||
|
|
|
@ -107,7 +107,7 @@ GEN_VXFORM(vmulesh, 4, 13),
|
|||
GEN_VXFORM_207(vmulesw, 4, 14),
|
||||
GEN_VXFORM(vslb, 2, 4),
|
||||
GEN_VXFORM(vslh, 2, 5),
|
||||
GEN_VXFORM(vslw, 2, 6),
|
||||
GEN_VXFORM_DUAL(vslw, vrlwnm, 2, 6, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_207(vsld, 2, 23),
|
||||
GEN_VXFORM(vsrb, 2, 8),
|
||||
GEN_VXFORM(vsrh, 2, 9),
|
||||
|
@ -122,7 +122,11 @@ GEN_VXFORM_300(vslv, 2, 29),
|
|||
GEN_VXFORM(vslo, 6, 16),
|
||||
GEN_VXFORM(vsro, 6, 17),
|
||||
GEN_VXFORM(vaddcuw, 0, 6),
|
||||
GEN_VXFORM(vsubcuw, 0, 22),
|
||||
GEN_HANDLER_E_2(vprtybw, 0x4, 0x1, 0x18, 8, 0, PPC_NONE, PPC2_ISA300),
|
||||
GEN_HANDLER_E_2(vprtybd, 0x4, 0x1, 0x18, 9, 0, PPC_NONE, PPC2_ISA300),
|
||||
GEN_HANDLER_E_2(vprtybq, 0x4, 0x1, 0x18, 10, 0, PPC_NONE, PPC2_ISA300),
|
||||
|
||||
GEN_VXFORM_DUAL(vsubcuw, xpnd04_1, 0, 22, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_DUAL(vadduhs, vmul10euq, 0, 9, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM(vadduws, 0, 10),
|
||||
|
@ -134,7 +138,7 @@ GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
|
|||
GEN_VXFORM(vsubuws, 0, 26),
|
||||
GEN_VXFORM(vsubsbs, 0, 28),
|
||||
GEN_VXFORM(vsubshs, 0, 29),
|
||||
GEN_VXFORM(vsubsws, 0, 30),
|
||||
GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_207(vadduqm, 0, 4),
|
||||
GEN_VXFORM_207(vaddcuq, 0, 5),
|
||||
GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
|
||||
|
@ -143,9 +147,9 @@ GEN_VXFORM_207(vsubcuq, 0, 21),
|
|||
GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
|
||||
GEN_VXFORM(vrlb, 2, 0),
|
||||
GEN_VXFORM(vrlh, 2, 1),
|
||||
GEN_VXFORM(vrlw, 2, 2),
|
||||
GEN_VXFORM_207(vrld, 2, 3),
|
||||
GEN_VXFORM(vsl, 2, 7),
|
||||
GEN_VXFORM_DUAL(vrlw, vrlwmi, 2, 2, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM_DUAL(vrld, vrldmi, 2, 3, PPC_NONE, PPC2_ALTIVEC_207),
|
||||
GEN_VXFORM_DUAL(vsl, vrldnm, 2, 7, PPC_ALTIVEC, PPC_NONE),
|
||||
GEN_VXFORM(vsr, 2, 11),
|
||||
GEN_VXFORM(vpkuhum, 7, 0),
|
||||
GEN_VXFORM(vpkuwum, 7, 1),
|
||||
|
|
|
@ -270,6 +270,7 @@ gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c
|
|||
check-qtest-ppc64-y += tests/endianness-test$(EXESUF)
|
||||
check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
|
||||
check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
|
||||
check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF)
|
||||
check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
|
||||
check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
|
||||
check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
|
||||
|
@ -644,6 +645,7 @@ tests/e1000-test$(EXESUF): tests/e1000-test.o
|
|||
tests/e1000e-test$(EXESUF): tests/e1000e-test.o $(libqos-pc-obj-y)
|
||||
tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
|
||||
tests/pcnet-test$(EXESUF): tests/pcnet-test.o
|
||||
tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
|
||||
tests/eepro100-test$(EXESUF): tests/eepro100-test.o
|
||||
tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
|
||||
tests/ne2000-test$(EXESUF): tests/ne2000-test.o
|
||||
|
|
|
@ -29,6 +29,7 @@ static testdef_t tests[] = {
|
|||
{ "ppc64", "ppce500", "", "U-Boot" },
|
||||
{ "ppc64", "prep", "", "Open Hack'Ware BIOS" },
|
||||
{ "ppc64", "pseries", "", "Open Firmware" },
|
||||
{ "ppc64", "powernv", "-cpu POWER9", "SkiBoot" },
|
||||
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
|
||||
{ "i386", "pc", "-device sga", "SGABIOS" },
|
||||
{ "i386", "q35", "-device sga", "SGABIOS" },
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* QTest testcase for PowerNV XSCOM bus
|
||||
*
|
||||
* Copyright (c) 2016, IBM Corporation.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "libqtest.h"
|
||||
|
||||
typedef enum PnvChipType {
|
||||
PNV_CHIP_POWER8E, /* AKA Murano (default) */
|
||||
PNV_CHIP_POWER8, /* AKA Venice */
|
||||
PNV_CHIP_POWER8NVL, /* AKA Naples */
|
||||
PNV_CHIP_POWER9, /* AKA Nimbus */
|
||||
} PnvChipType;
|
||||
|
||||
typedef struct PnvChip {
|
||||
PnvChipType chip_type;
|
||||
const char *cpu_model;
|
||||
uint64_t xscom_base;
|
||||
uint64_t xscom_core_base;
|
||||
uint64_t cfam_id;
|
||||
uint32_t first_core;
|
||||
} PnvChip;
|
||||
|
||||
static const PnvChip pnv_chips[] = {
|
||||
{
|
||||
.chip_type = PNV_CHIP_POWER8,
|
||||
.cpu_model = "POWER8",
|
||||
.xscom_base = 0x0003fc0000000000ull,
|
||||
.xscom_core_base = 0x10000000ull,
|
||||
.cfam_id = 0x220ea04980000000ull,
|
||||
.first_core = 0x1,
|
||||
}, {
|
||||
.chip_type = PNV_CHIP_POWER8NVL,
|
||||
.cpu_model = "POWER8NVL",
|
||||
.xscom_base = 0x0003fc0000000000ull,
|
||||
.xscom_core_base = 0x10000000ull,
|
||||
.cfam_id = 0x120d304980000000ull,
|
||||
.first_core = 0x1,
|
||||
}, {
|
||||
.chip_type = PNV_CHIP_POWER9,
|
||||
.cpu_model = "POWER9",
|
||||
.xscom_base = 0x000603fc00000000ull,
|
||||
.xscom_core_base = 0x0ull,
|
||||
.cfam_id = 0x100d104980000000ull,
|
||||
.first_core = 0x20,
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
|
||||
{
|
||||
uint64_t addr = chip->xscom_base;
|
||||
|
||||
if (chip->chip_type == PNV_CHIP_POWER9) {
|
||||
addr |= ((uint64_t) pcba << 3);
|
||||
} else {
|
||||
addr |= (((uint64_t) pcba << 4) & ~0xffull) |
|
||||
(((uint64_t) pcba << 3) & 0x78);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
static uint64_t pnv_xscom_read(const PnvChip *chip, uint32_t pcba)
|
||||
{
|
||||
return readq(pnv_xscom_addr(chip, pcba));
|
||||
}
|
||||
|
||||
static void test_xscom_cfam_id(const PnvChip *chip)
|
||||
{
|
||||
uint64_t f000f = pnv_xscom_read(chip, 0xf000f);
|
||||
|
||||
g_assert_cmphex(f000f, ==, chip->cfam_id);
|
||||
}
|
||||
|
||||
static void test_cfam_id(const void *data)
|
||||
{
|
||||
char *args;
|
||||
const PnvChip *chip = data;
|
||||
|
||||
args = g_strdup_printf("-M powernv,accel=tcg -cpu %s", chip->cpu_model);
|
||||
|
||||
qtest_start(args);
|
||||
test_xscom_cfam_id(chip);
|
||||
qtest_quit(global_qtest);
|
||||
|
||||
g_free(args);
|
||||
}
|
||||
|
||||
#define PNV_XSCOM_EX_CORE_BASE(chip, i) \
|
||||
((chip)->xscom_core_base | (((uint64_t)i) << 24))
|
||||
#define PNV_XSCOM_EX_DTS_RESULT0 0x50000
|
||||
|
||||
static void test_xscom_core(const PnvChip *chip)
|
||||
{
|
||||
uint32_t first_core_dts0 =
|
||||
PNV_XSCOM_EX_CORE_BASE(chip, chip->first_core) |
|
||||
PNV_XSCOM_EX_DTS_RESULT0;
|
||||
uint64_t dts0 = pnv_xscom_read(chip, first_core_dts0);
|
||||
|
||||
g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull);
|
||||
}
|
||||
|
||||
static void test_core(const void *data)
|
||||
{
|
||||
char *args;
|
||||
const PnvChip *chip = data;
|
||||
|
||||
args = g_strdup_printf("-M powernv,accel=tcg -cpu %s", chip->cpu_model);
|
||||
|
||||
qtest_start(args);
|
||||
test_xscom_core(chip);
|
||||
qtest_quit(global_qtest);
|
||||
|
||||
g_free(args);
|
||||
}
|
||||
|
||||
static void add_test(const char *name, void (*test)(const void *data))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
|
||||
char *tname = g_strdup_printf("pnv-xscom/%s/%s", name,
|
||||
pnv_chips[i].cpu_model);
|
||||
qtest_add_data_func(tname, &pnv_chips[i], test);
|
||||
g_free(tname);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
add_test("cfam_id", test_cfam_id);
|
||||
add_test("core", test_core);
|
||||
return g_test_run();
|
||||
}
|
Loading…
Reference in New Issue