mirror of https://github.com/xemu-project/xemu.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 } },
|
{ "vrlh", VX(4, 68), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||||
{ "vrlw", VX(4, 132), 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 } },
|
{ "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 } },
|
{ "vsel", VXA(4, 42), VXA_MASK, PPCVEC, { VD, VA, VB, VC } },
|
||||||
{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } },
|
{ "vsl", VX(4, 452), VX_MASK, PPCVEC, { VD, VA, VB } },
|
||||||
{ "vslb", VX(4, 260), 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/osdep.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "cpu.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));
|
qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
|
||||||
}
|
}
|
||||||
for (i = 0; i < size; i++) {
|
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];
|
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));
|
CPUState *cs = CPU(DEVICE(pc->threads));
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(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;
|
CPUPPCState *env = &cpu->env;
|
||||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||||
uint32_t servers_prop[smt_threads];
|
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",
|
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
|
||||||
pa_features, sizeof(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 */
|
/* Build interrupt servers properties */
|
||||||
for (i = 0; i < smt_threads; i++) {
|
for (i = 0; i < smt_threads; i++) {
|
||||||
servers_prop[i] = cpu_to_be32(pc->pir + 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->cores_mask = POWER8E_CORE_MASK;
|
||||||
k->core_pir = pnv_chip_core_pir_p8;
|
k->core_pir = pnv_chip_core_pir_p8;
|
||||||
k->xscom_base = 0x003fc0000000000ull;
|
k->xscom_base = 0x003fc0000000000ull;
|
||||||
|
k->xscom_core_base = 0x10000000ull;
|
||||||
dc->desc = "PowerNV Chip POWER8E";
|
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->cores_mask = POWER8_CORE_MASK;
|
||||||
k->core_pir = pnv_chip_core_pir_p8;
|
k->core_pir = pnv_chip_core_pir_p8;
|
||||||
k->xscom_base = 0x003fc0000000000ull;
|
k->xscom_base = 0x003fc0000000000ull;
|
||||||
|
k->xscom_core_base = 0x10000000ull;
|
||||||
dc->desc = "PowerNV Chip POWER8";
|
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->cores_mask = POWER8_CORE_MASK;
|
||||||
k->core_pir = pnv_chip_core_pir_p8;
|
k->core_pir = pnv_chip_core_pir_p8;
|
||||||
k->xscom_base = 0x003fc0000000000ull;
|
k->xscom_base = 0x003fc0000000000ull;
|
||||||
|
k->xscom_core_base = 0x10000000ull;
|
||||||
dc->desc = "PowerNV Chip POWER8NVL";
|
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->cores_mask = POWER9_CORE_MASK;
|
||||||
k->core_pir = pnv_chip_core_pir_p9;
|
k->core_pir = pnv_chip_core_pir_p9;
|
||||||
k->xscom_base = 0x00603fc00000000ull;
|
k->xscom_base = 0x00603fc00000000ull;
|
||||||
|
k->xscom_core_base = 0x0ull;
|
||||||
dc->desc = "PowerNV Chip POWER9";
|
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;
|
chip->cores_mask &= pcc->cores_mask;
|
||||||
|
|
||||||
/* now that we have a sane layout, let check the number of cores */
|
/* 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) {
|
if (chip->nr_cores > cores_max) {
|
||||||
error_setg(errp, "warning: too many cores for chip ! Limit is %d",
|
error_setg(errp, "warning: too many cores for chip ! Limit is %d",
|
||||||
cores_max);
|
cores_max);
|
||||||
|
@ -695,7 +695,9 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
|
||||||
object_unref(OBJECT(pnv_core));
|
object_unref(OBJECT(pnv_core));
|
||||||
|
|
||||||
/* Each core has an XSCOM MMIO region */
|
/* 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);
|
&PNV_CORE(pnv_core)->xscom_regs);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "hw/ppc/ppc.h"
|
#include "hw/ppc/ppc.h"
|
||||||
#include "hw/ppc/pnv.h"
|
#include "hw/ppc/pnv.h"
|
||||||
#include "hw/ppc/pnv_core.h"
|
#include "hw/ppc/pnv_core.h"
|
||||||
|
#include "hw/ppc/pnv_xscom.h"
|
||||||
|
|
||||||
static void powernv_cpu_reset(void *opaque)
|
static void powernv_cpu_reset(void *opaque)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,8 +23,9 @@
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
|
||||||
#include "hw/ppc/pnv_lpc.h"
|
|
||||||
#include "hw/ppc/pnv.h"
|
#include "hw/ppc/pnv.h"
|
||||||
|
#include "hw/ppc/pnv_lpc.h"
|
||||||
|
#include "hw/ppc/pnv_xscom.h"
|
||||||
#include "hw/ppc/fdt.h"
|
#include "hw/ppc/fdt.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
|
|
||||||
#include "hw/ppc/fdt.h"
|
#include "hw/ppc/fdt.h"
|
||||||
#include "hw/ppc/pnv_xscom.h"
|
|
||||||
#include "hw/ppc/pnv.h"
|
#include "hw/ppc/pnv.h"
|
||||||
|
#include "hw/ppc/pnv_xscom.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ static uint64_t xscom_read(void *opaque, hwaddr addr, unsigned width)
|
||||||
goto complete;
|
goto complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = address_space_ldq(&chip->xscom_as, pcba << 3, MEMTXATTRS_UNSPECIFIED,
|
val = address_space_ldq(&chip->xscom_as, (uint64_t) pcba << 3,
|
||||||
&result);
|
MEMTXATTRS_UNSPECIFIED, &result);
|
||||||
if (result != MEMTX_OK) {
|
if (result != MEMTX_OK) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "XSCOM read failed at @0x%"
|
qemu_log_mask(LOG_GUEST_ERROR, "XSCOM read failed at @0x%"
|
||||||
HWADDR_PRIx " pcba=0x%08x\n", addr, pcba);
|
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;
|
goto complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
address_space_stq(&chip->xscom_as, pcba << 3, val, MEMTXATTRS_UNSPECIFIED,
|
address_space_stq(&chip->xscom_as, (uint64_t) pcba << 3, val,
|
||||||
&result);
|
MEMTXATTRS_UNSPECIFIED, &result);
|
||||||
if (result != MEMTX_OK) {
|
if (result != MEMTX_OK) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "XSCOM write failed at @0x%"
|
qemu_log_mask(LOG_GUEST_ERROR, "XSCOM write failed at @0x%"
|
||||||
HWADDR_PRIx " pcba=0x%08x data=0x%" PRIx64 "\n",
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool version_before_3(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
return version_id < 3;
|
||||||
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_spapr_pci = {
|
static const VMStateDescription vmstate_spapr_pci = {
|
||||||
.name = "spapr_pci",
|
.name = "spapr_pci",
|
||||||
.version_id = 2,
|
.version_id = 3,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.pre_save = spapr_pci_pre_save,
|
.pre_save = spapr_pci_pre_save,
|
||||||
.post_load = spapr_pci_post_load,
|
.post_load = spapr_pci_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
|
VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState),
|
||||||
VMSTATE_UINT32_EQUAL(dma_liobn[0], sPAPRPHBState),
|
VMSTATE_UNUSED_TEST(version_before_3,
|
||||||
VMSTATE_UINT64_EQUAL(mem_win_addr, sPAPRPHBState),
|
sizeof(uint32_t) /* dma_liobn[0] */
|
||||||
VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
|
+ sizeof(uint64_t) /* mem_win_addr */
|
||||||
VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
|
+ sizeof(uint64_t) /* mem_win_size */
|
||||||
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
|
+ sizeof(uint64_t) /* io_win_addr */
|
||||||
|
+ sizeof(uint64_t) /* io_win_size */),
|
||||||
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
|
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
|
||||||
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
|
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
|
||||||
VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
|
VMSTATE_INT32(msi_devs_num, sPAPRPHBState),
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "hw/ppc/pnv_xscom.h"
|
|
||||||
#include "hw/ppc/pnv_lpc.h"
|
#include "hw/ppc/pnv_lpc.h"
|
||||||
|
|
||||||
#define TYPE_PNV_CHIP "powernv-chip"
|
#define TYPE_PNV_CHIP "powernv-chip"
|
||||||
|
@ -70,6 +69,7 @@ typedef struct PnvChipClass {
|
||||||
uint64_t cores_mask;
|
uint64_t cores_mask;
|
||||||
|
|
||||||
hwaddr xscom_base;
|
hwaddr xscom_base;
|
||||||
|
hwaddr xscom_core_base;
|
||||||
|
|
||||||
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
|
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
|
||||||
} PnvChipClass;
|
} PnvChipClass;
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
typedef struct PnvChip PnvChip;
|
|
||||||
|
|
||||||
typedef struct PnvXScomInterface {
|
typedef struct PnvXScomInterface {
|
||||||
Object parent;
|
Object parent;
|
||||||
} PnvXScomInterface;
|
} PnvXScomInterface;
|
||||||
|
@ -42,7 +40,7 @@ typedef struct PnvXScomInterfaceClass {
|
||||||
} 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
|
* GPIO 0x1100xxxx
|
||||||
* SCOM 0x1101xxxx
|
* SCOM 0x1101xxxx
|
||||||
|
@ -56,8 +54,7 @@ typedef struct PnvXScomInterfaceClass {
|
||||||
* PCB SLAVE 0x110Fxxxx
|
* PCB SLAVE 0x110Fxxxx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PNV_XSCOM_EX_BASE 0x10000000
|
#define PNV_XSCOM_EX_CORE_BASE(base, i) (base | (((uint64_t)i) << 24))
|
||||||
#define PNV_XSCOM_EX_CORE_BASE(i) (PNV_XSCOM_EX_BASE | (((uint64_t)i) << 24))
|
|
||||||
#define PNV_XSCOM_EX_CORE_SIZE 0x100000
|
#define PNV_XSCOM_EX_CORE_SIZE 0x100000
|
||||||
|
|
||||||
#define PNV_XSCOM_LPC_BASE 0xb0020
|
#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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
#if defined(TODO)
|
||||||
POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6,
|
POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, 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
|
#endif
|
||||||
POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7,
|
POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7,
|
||||||
"POWER7 v2.3")
|
"POWER7 v2.3")
|
||||||
|
|
|
@ -549,8 +549,6 @@ enum {
|
||||||
CPU_POWERPC_POWER5 = 0x003A0203,
|
CPU_POWERPC_POWER5 = 0x003A0203,
|
||||||
CPU_POWERPC_POWER5P_v21 = 0x003B0201,
|
CPU_POWERPC_POWER5P_v21 = 0x003B0201,
|
||||||
CPU_POWERPC_POWER6 = 0x003E0000,
|
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_POWER_SERVER_MASK = 0xFFFF0000,
|
||||||
CPU_POWERPC_POWER7_BASE = 0x003F0000,
|
CPU_POWERPC_POWER7_BASE = 0x003F0000,
|
||||||
CPU_POWERPC_POWER7_v23 = 0x003F0203,
|
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_VPU: /* Vector unavailable exception */
|
||||||
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
|
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
|
||||||
case POWERPC_EXCP_FU: /* Facility unavailable exception */
|
case POWERPC_EXCP_FU: /* Facility unavailable exception */
|
||||||
|
#ifdef TARGET_PPC64
|
||||||
|
env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
||||||
LOG_EXCP("PIT exception\n");
|
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(vsrv, void, avr, avr, avr)
|
||||||
DEF_HELPER_3(vslv, void, avr, avr, avr)
|
DEF_HELPER_3(vslv, void, avr, avr, avr)
|
||||||
DEF_HELPER_3(vaddcuw, 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_3(vsubcuw, void, avr, avr, avr)
|
||||||
DEF_HELPER_2(lvsl, void, avr, tl)
|
DEF_HELPER_2(lvsl, void, avr, tl)
|
||||||
DEF_HELPER_2(lvsr, 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_4(vminfp, void, env, avr, avr, avr)
|
||||||
DEF_HELPER_3(vrefp, void, env, avr, avr)
|
DEF_HELPER_3(vrefp, void, env, avr, avr)
|
||||||
DEF_HELPER_3(vrsqrtefp, 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(vmaddfp, void, env, avr, avr, avr, avr)
|
||||||
DEF_HELPER_5(vnmsubfp, void, env, avr, avr, avr, avr)
|
DEF_HELPER_5(vnmsubfp, void, env, avr, avr, avr, avr)
|
||||||
DEF_HELPER_3(vexptefp, void, env, 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(bcdadd, i32, avr, avr, avr, i32)
|
||||||
DEF_HELPER_4(bcdsub, 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(xsadddp, void, env, i32)
|
||||||
DEF_HELPER_2(xssubdp, void, env, i32)
|
DEF_HELPER_2(xssubdp, void, env, i32)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "internal.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "exec/helper-proto.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) \
|
#define VARITH_DO(name, op, element) \
|
||||||
void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
|
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,
|
void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
|
||||||
ppc_avr_t *c)
|
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_PREF 0xD
|
||||||
#define BCD_NEG_ALT 0xB
|
#define BCD_NEG_ALT 0xB
|
||||||
#define BCD_PLUS_ALT_2 0xE
|
#define BCD_PLUS_ALT_2 0xE
|
||||||
|
#define NATIONAL_PLUS 0x2B
|
||||||
|
#define NATIONAL_NEG 0x2D
|
||||||
|
|
||||||
#if defined(HOST_WORDS_BIGENDIAN)
|
#if defined(HOST_WORDS_BIGENDIAN)
|
||||||
#define BCD_DIG_BYTE(n) (15 - (n/2))
|
#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)
|
static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
|
||||||
{
|
{
|
||||||
int i;
|
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);
|
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)
|
void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
|
||||||
{
|
{
|
||||||
int i;
|
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 "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "internal.h"
|
||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg-op.h"
|
#include "tcg-op.h"
|
||||||
|
@ -561,34 +562,6 @@ EXTRACT_HELPER(DCM, 10, 6)
|
||||||
/* DFP Z23-form */
|
/* DFP Z23-form */
|
||||||
EXTRACT_HELPER(RMC, 9, 2)
|
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(xT, 0, 1, 21, 5);
|
||||||
EXTRACT_HELPER_SPLIT(xS, 0, 1, 21, 5);
|
EXTRACT_HELPER_SPLIT(xS, 0, 1, 21, 5);
|
||||||
EXTRACT_HELPER_SPLIT(xA, 2, 1, 16, 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(vslb, 2, 4);
|
||||||
GEN_VXFORM(vslh, 2, 5);
|
GEN_VXFORM(vslh, 2, 5);
|
||||||
GEN_VXFORM(vslw, 2, 6);
|
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(vsld, 2, 23);
|
||||||
GEN_VXFORM(vsrb, 2, 8);
|
GEN_VXFORM(vsrb, 2, 8);
|
||||||
GEN_VXFORM(vsrh, 2, 9);
|
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(vrlb, 2, 0);
|
||||||
GEN_VXFORM(vrlh, 2, 1);
|
GEN_VXFORM(vrlh, 2, 1);
|
||||||
GEN_VXFORM(vrlw, 2, 2);
|
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(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(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(vsr, 2, 11);
|
||||||
GEN_VXFORM_ENV(vpkuhum, 7, 0);
|
GEN_VXFORM_ENV(vpkuhum, 7, 0);
|
||||||
GEN_VXFORM_ENV(vpkuwum, 7, 1);
|
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(vrfin, 5, 8);
|
||||||
GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
|
GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
|
||||||
GEN_VXFORM_NOA_ENV(vrfiz, 5, 9);
|
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) \
|
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
|
||||||
static void glue(gen_, name)(DisasContext *ctx) \
|
static void glue(gen_, name)(DisasContext *ctx) \
|
||||||
|
@ -945,8 +960,79 @@ static void gen_##op(DisasContext *ctx) \
|
||||||
tcg_temp_free_i32(ps); \
|
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(bcdadd)
|
||||||
GEN_BCD(bcdsub)
|
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, \
|
GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
|
||||||
bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
|
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_NOA
|
||||||
#undef GEN_VXFORM_UIMM
|
#undef GEN_VXFORM_UIMM
|
||||||
#undef GEN_VAFORM_PAIRED
|
#undef GEN_VAFORM_PAIRED
|
||||||
|
|
||||||
|
#undef GEN_BCD2
|
||||||
|
|
|
@ -107,7 +107,7 @@ GEN_VXFORM(vmulesh, 4, 13),
|
||||||
GEN_VXFORM_207(vmulesw, 4, 14),
|
GEN_VXFORM_207(vmulesw, 4, 14),
|
||||||
GEN_VXFORM(vslb, 2, 4),
|
GEN_VXFORM(vslb, 2, 4),
|
||||||
GEN_VXFORM(vslh, 2, 5),
|
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_207(vsld, 2, 23),
|
||||||
GEN_VXFORM(vsrb, 2, 8),
|
GEN_VXFORM(vsrb, 2, 8),
|
||||||
GEN_VXFORM(vsrh, 2, 9),
|
GEN_VXFORM(vsrh, 2, 9),
|
||||||
|
@ -122,7 +122,11 @@ GEN_VXFORM_300(vslv, 2, 29),
|
||||||
GEN_VXFORM(vslo, 6, 16),
|
GEN_VXFORM(vslo, 6, 16),
|
||||||
GEN_VXFORM(vsro, 6, 17),
|
GEN_VXFORM(vsro, 6, 17),
|
||||||
GEN_VXFORM(vaddcuw, 0, 6),
|
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(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE),
|
||||||
GEN_VXFORM_DUAL(vadduhs, vmul10euq, 0, 9, PPC_ALTIVEC, PPC_NONE),
|
GEN_VXFORM_DUAL(vadduhs, vmul10euq, 0, 9, PPC_ALTIVEC, PPC_NONE),
|
||||||
GEN_VXFORM(vadduws, 0, 10),
|
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(vsubuws, 0, 26),
|
||||||
GEN_VXFORM(vsubsbs, 0, 28),
|
GEN_VXFORM(vsubsbs, 0, 28),
|
||||||
GEN_VXFORM(vsubshs, 0, 29),
|
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(vadduqm, 0, 4),
|
||||||
GEN_VXFORM_207(vaddcuq, 0, 5),
|
GEN_VXFORM_207(vaddcuq, 0, 5),
|
||||||
GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
|
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_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
|
||||||
GEN_VXFORM(vrlb, 2, 0),
|
GEN_VXFORM(vrlb, 2, 0),
|
||||||
GEN_VXFORM(vrlh, 2, 1),
|
GEN_VXFORM(vrlh, 2, 1),
|
||||||
GEN_VXFORM(vrlw, 2, 2),
|
GEN_VXFORM_DUAL(vrlw, vrlwmi, 2, 2, PPC_ALTIVEC, PPC_NONE),
|
||||||
GEN_VXFORM_207(vrld, 2, 3),
|
GEN_VXFORM_DUAL(vrld, vrldmi, 2, 3, PPC_NONE, PPC2_ALTIVEC_207),
|
||||||
GEN_VXFORM(vsl, 2, 7),
|
GEN_VXFORM_DUAL(vsl, vrldnm, 2, 7, PPC_ALTIVEC, PPC_NONE),
|
||||||
GEN_VXFORM(vsr, 2, 11),
|
GEN_VXFORM(vsr, 2, 11),
|
||||||
GEN_VXFORM(vpkuhum, 7, 0),
|
GEN_VXFORM(vpkuhum, 7, 0),
|
||||||
GEN_VXFORM(vpkuwum, 7, 1),
|
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/endianness-test$(EXESUF)
|
||||||
check-qtest-ppc64-y += tests/boot-order-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/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/drive_del-test$(EXESUF)
|
||||||
check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
|
check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
|
||||||
check-qtest-ppc64-y += tests/boot-serial-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/e1000e-test$(EXESUF): tests/e1000e-test.o $(libqos-pc-obj-y)
|
||||||
tests/rtl8139-test$(EXESUF): tests/rtl8139-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/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/eepro100-test$(EXESUF): tests/eepro100-test.o
|
||||||
tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
|
tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
|
||||||
tests/ne2000-test$(EXESUF): tests/ne2000-test.o
|
tests/ne2000-test$(EXESUF): tests/ne2000-test.o
|
||||||
|
|
|
@ -29,6 +29,7 @@ static testdef_t tests[] = {
|
||||||
{ "ppc64", "ppce500", "", "U-Boot" },
|
{ "ppc64", "ppce500", "", "U-Boot" },
|
||||||
{ "ppc64", "prep", "", "Open Hack'Ware BIOS" },
|
{ "ppc64", "prep", "", "Open Hack'Ware BIOS" },
|
||||||
{ "ppc64", "pseries", "", "Open Firmware" },
|
{ "ppc64", "pseries", "", "Open Firmware" },
|
||||||
|
{ "ppc64", "powernv", "-cpu POWER9", "SkiBoot" },
|
||||||
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
|
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
|
||||||
{ "i386", "pc", "-device sga", "SGABIOS" },
|
{ "i386", "pc", "-device sga", "SGABIOS" },
|
||||||
{ "i386", "q35", "-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