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>
master
Stefan Hajnoczi 2016-11-15 11:59:40 +00:00
commit 8a7b5c1893
22 changed files with 609 additions and 74 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

50
target-ppc/internal.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

140
tests/pnv-xscom-test.c Normal file
View File

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