*** NOTE ***

This replaces the previous PR for tags/pull-ppc-for-9.1-1-20240524
 
 * Fix an interesting TLB invalidate race
 * Implement more instructions with decodetree
 * Add the POWER8/9/10 BHRB facility
 * Add missing instructions, registers, SMT support
 * First round of a big MMU xlate cleanup
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmZP1bsACgkQZ7MCdqhi
 HK7TuQ/7BQugpF2yOYroQmo0Yl4RPfFp6ACqfYQgehcGegg3SWpEselTeOJla3G9
 UyVd0mlWf7DciYi61qit/WyLOeuRXMtRjrnFLV2wz9o7D/Ey5/aLQfUL4oCDt/i2
 hmmq3ZAcr7WWxaz338pLJx9gIVjaNiqSoRz9HgHNkQq0pxkbEo1eSjZ6QLSvqYC2
 dwtJHywFrHNo14aq1Nc7PZ5MFxNN6t7hm7KRHKFrt8Obar15n64MSHyRvMzHI9EO
 RgNzz9/qe5yvJ4kmaNiZjntxojXCBUhhlCTtaDIG1LDBc2yNG5VWQUnwThvyNxxX
 h+Ia4Pv7blXikQ6RuqsvFyrLCgUvwXwBiQwiQCJyITk0asLyJVwhkUpiI/jJvOun
 AujSA/6e2pbSe4RUZytkzygx2KVODrVtcSoOvo8kRw+2aTOWMv7DbfBalmWJQWgx
 0xSeuUz22eNKEL2XbZWNM5v0OgXUXIs9BVeCqn7RB4lC2RNi72v111UPuKYq6Ijx
 SHWQMGPGu9FNBsIdriclRWXVXHpVHz/s/l8AJT8ad6E57UHVk5zCPrbFZFImvQkL
 E7xlctijeST8V5qGyBPG3M4aPoER9+6J32ORSx7KwDwr+fzkbNUXC8UUC4OjAZ+d
 2vhie9Vs5xWq/E8gGovTymeQ4yHArobDz/j7+rrr0qeppnKLWjM=
 =jHL7
 -----END PGP SIGNATURE-----

Merge tag 'pull-ppc-for-9.1-1-20240524-1' of https://gitlab.com/npiggin/qemu into staging

*** NOTE ***
This replaces the previous PR for tags/pull-ppc-for-9.1-1-20240524

* Fix an interesting TLB invalidate race
* Implement more instructions with decodetree
* Add the POWER8/9/10 BHRB facility
* Add missing instructions, registers, SMT support
* First round of a big MMU xlate cleanup

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmZP1bsACgkQZ7MCdqhi
# HK7TuQ/7BQugpF2yOYroQmo0Yl4RPfFp6ACqfYQgehcGegg3SWpEselTeOJla3G9
# UyVd0mlWf7DciYi61qit/WyLOeuRXMtRjrnFLV2wz9o7D/Ey5/aLQfUL4oCDt/i2
# hmmq3ZAcr7WWxaz338pLJx9gIVjaNiqSoRz9HgHNkQq0pxkbEo1eSjZ6QLSvqYC2
# dwtJHywFrHNo14aq1Nc7PZ5MFxNN6t7hm7KRHKFrt8Obar15n64MSHyRvMzHI9EO
# RgNzz9/qe5yvJ4kmaNiZjntxojXCBUhhlCTtaDIG1LDBc2yNG5VWQUnwThvyNxxX
# h+Ia4Pv7blXikQ6RuqsvFyrLCgUvwXwBiQwiQCJyITk0asLyJVwhkUpiI/jJvOun
# AujSA/6e2pbSe4RUZytkzygx2KVODrVtcSoOvo8kRw+2aTOWMv7DbfBalmWJQWgx
# 0xSeuUz22eNKEL2XbZWNM5v0OgXUXIs9BVeCqn7RB4lC2RNi72v111UPuKYq6Ijx
# SHWQMGPGu9FNBsIdriclRWXVXHpVHz/s/l8AJT8ad6E57UHVk5zCPrbFZFImvQkL
# E7xlctijeST8V5qGyBPG3M4aPoER9+6J32ORSx7KwDwr+fzkbNUXC8UUC4OjAZ+d
# 2vhie9Vs5xWq/E8gGovTymeQ4yHArobDz/j7+rrr0qeppnKLWjM=
# =jHL7
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 23 May 2024 04:48:11 PM PDT
# gpg:                using RSA key 4E437DDA56616F4329B0A79567B30276A8621CAE
# gpg: Good signature from "Nicholas Piggin <npiggin@gmail.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 4E43 7DDA 5661 6F43 29B0  A795 67B3 0276 A862 1CAE

* tag 'pull-ppc-for-9.1-1-20240524-1' of https://gitlab.com/npiggin/qemu: (72 commits)
  target/ppc: Remove pp_check() and reuse ppc_hash32_pp_prot()
  target/ppc: Move out BookE and related MMU functions from mmu_common.c
  target/ppc: Add a function to check for page protection bit
  target/ppc/mmu-radix64.c: Drop a local variable
  target/ppc/mmu-hash32.c: Drop a local variable
  target/ppc: Split off common embedded TLB init
  target/ppc: Remove id_tlbs flag from CPU env
  target/ppc: Move mmu_ctx_t type to mmu_common.c
  target/ppc: Transform ppc_jumbo_xlate() into ppc_6xx_xlate()
  target/ppc: Split off 40x cases from ppc_jumbo_xlate()
  target/ppc: Split off real mode handling from get_physical_address_wtlb()
  target/ppc: Simplify ppc_booke_xlate() part 2
  target/ppc: Simplify ppc_booke_xlate() part 1
  target/ppc: Split off BookE handling from ppc_jumbo_xlate()
  target/ppc: Remove BookE from direct store handling
  target/ppc: Don't use mmu_ctx_t in mmubooke206_get_physical_address()
  target/ppc: Don't use mmu_ctx_t in mmubooke_get_physical_address()
  target/ppc: Don't use mmu_ctx_t for mmu40x_get_physical_address()
  target/ppc: Replace hard coded constants in ppc_jumbo_xlate()
  target/ppc: Deindent ppc_jumbo_xlate()
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-05-23 22:09:59 -07:00
commit ffdd099a78
43 changed files with 3271 additions and 2996 deletions

View File

@ -418,12 +418,9 @@ void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap)
{ {
tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap); tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap);
if (cpu->created && !qemu_cpu_is_self(cpu)) { assert_cpu_is_self(cpu);
async_run_on_cpu(cpu, tlb_flush_by_mmuidx_async_work,
RUN_ON_CPU_HOST_INT(idxmap)); tlb_flush_by_mmuidx_async_work(cpu, RUN_ON_CPU_HOST_INT(idxmap));
} else {
tlb_flush_by_mmuidx_async_work(cpu, RUN_ON_CPU_HOST_INT(idxmap));
}
} }
void tlb_flush(CPUState *cpu) void tlb_flush(CPUState *cpu)
@ -431,21 +428,6 @@ void tlb_flush(CPUState *cpu)
tlb_flush_by_mmuidx(cpu, ALL_MMUIDX_BITS); tlb_flush_by_mmuidx(cpu, ALL_MMUIDX_BITS);
} }
void tlb_flush_by_mmuidx_all_cpus(CPUState *src_cpu, uint16_t idxmap)
{
const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work;
tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap);
flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap));
fn(src_cpu, RUN_ON_CPU_HOST_INT(idxmap));
}
void tlb_flush_all_cpus(CPUState *src_cpu)
{
tlb_flush_by_mmuidx_all_cpus(src_cpu, ALL_MMUIDX_BITS);
}
void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap) void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap)
{ {
const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work;
@ -627,28 +609,12 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap)
{ {
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap); tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap);
assert_cpu_is_self(cpu);
/* This should already be page aligned */ /* This should already be page aligned */
addr &= TARGET_PAGE_MASK; addr &= TARGET_PAGE_MASK;
if (qemu_cpu_is_self(cpu)) { tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap);
tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap);
} else if (idxmap < TARGET_PAGE_SIZE) {
/*
* Most targets have only a few mmu_idx. In the case where
* we can stuff idxmap into the low TARGET_PAGE_BITS, avoid
* allocating memory for this operation.
*/
async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_1,
RUN_ON_CPU_TARGET_PTR(addr | idxmap));
} else {
TLBFlushPageByMMUIdxData *d = g_new(TLBFlushPageByMMUIdxData, 1);
/* Otherwise allocate a structure, freed by the worker. */
d->addr = addr;
d->idxmap = idxmap;
async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_2,
RUN_ON_CPU_HOST_PTR(d));
}
} }
void tlb_flush_page(CPUState *cpu, vaddr addr) void tlb_flush_page(CPUState *cpu, vaddr addr)
@ -656,46 +622,6 @@ void tlb_flush_page(CPUState *cpu, vaddr addr)
tlb_flush_page_by_mmuidx(cpu, addr, ALL_MMUIDX_BITS); tlb_flush_page_by_mmuidx(cpu, addr, ALL_MMUIDX_BITS);
} }
void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, vaddr addr,
uint16_t idxmap)
{
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
/* This should already be page aligned */
addr &= TARGET_PAGE_MASK;
/*
* Allocate memory to hold addr+idxmap only when needed.
* See tlb_flush_page_by_mmuidx for details.
*/
if (idxmap < TARGET_PAGE_SIZE) {
flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1,
RUN_ON_CPU_TARGET_PTR(addr | idxmap));
} else {
CPUState *dst_cpu;
/* Allocate a separate data block for each destination cpu. */
CPU_FOREACH(dst_cpu) {
if (dst_cpu != src_cpu) {
TLBFlushPageByMMUIdxData *d
= g_new(TLBFlushPageByMMUIdxData, 1);
d->addr = addr;
d->idxmap = idxmap;
async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2,
RUN_ON_CPU_HOST_PTR(d));
}
}
}
tlb_flush_page_by_mmuidx_async_0(src_cpu, addr, idxmap);
}
void tlb_flush_page_all_cpus(CPUState *src, vaddr addr)
{
tlb_flush_page_by_mmuidx_all_cpus(src, addr, ALL_MMUIDX_BITS);
}
void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
vaddr addr, vaddr addr,
uint16_t idxmap) uint16_t idxmap)
@ -851,6 +777,8 @@ void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
{ {
TLBFlushRangeData d; TLBFlushRangeData d;
assert_cpu_is_self(cpu);
/* /*
* If all bits are significant, and len is small, * If all bits are significant, and len is small,
* this devolves to tlb_flush_page. * this devolves to tlb_flush_page.
@ -871,14 +799,7 @@ void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
d.idxmap = idxmap; d.idxmap = idxmap;
d.bits = bits; d.bits = bits;
if (qemu_cpu_is_self(cpu)) { tlb_flush_range_by_mmuidx_async_0(cpu, d);
tlb_flush_range_by_mmuidx_async_0(cpu, d);
} else {
/* Otherwise allocate a structure, freed by the worker. */
TLBFlushRangeData *p = g_memdup(&d, sizeof(d));
async_run_on_cpu(cpu, tlb_flush_range_by_mmuidx_async_1,
RUN_ON_CPU_HOST_PTR(p));
}
} }
void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr, void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr,
@ -887,54 +808,6 @@ void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr,
tlb_flush_range_by_mmuidx(cpu, addr, TARGET_PAGE_SIZE, idxmap, bits); tlb_flush_range_by_mmuidx(cpu, addr, TARGET_PAGE_SIZE, idxmap, bits);
} }
void tlb_flush_range_by_mmuidx_all_cpus(CPUState *src_cpu,
vaddr addr, vaddr len,
uint16_t idxmap, unsigned bits)
{
TLBFlushRangeData d;
CPUState *dst_cpu;
/*
* If all bits are significant, and len is small,
* this devolves to tlb_flush_page.
*/
if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) {
tlb_flush_page_by_mmuidx_all_cpus(src_cpu, addr, idxmap);
return;
}
/* If no page bits are significant, this devolves to tlb_flush. */
if (bits < TARGET_PAGE_BITS) {
tlb_flush_by_mmuidx_all_cpus(src_cpu, idxmap);
return;
}
/* This should already be page aligned */
d.addr = addr & TARGET_PAGE_MASK;
d.len = len;
d.idxmap = idxmap;
d.bits = bits;
/* Allocate a separate data block for each destination cpu. */
CPU_FOREACH(dst_cpu) {
if (dst_cpu != src_cpu) {
TLBFlushRangeData *p = g_memdup(&d, sizeof(d));
async_run_on_cpu(dst_cpu,
tlb_flush_range_by_mmuidx_async_1,
RUN_ON_CPU_HOST_PTR(p));
}
}
tlb_flush_range_by_mmuidx_async_0(src_cpu, d);
}
void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *src_cpu,
vaddr addr, uint16_t idxmap,
unsigned bits)
{
tlb_flush_range_by_mmuidx_all_cpus(src_cpu, addr, TARGET_PAGE_SIZE,
idxmap, bits);
}
void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
vaddr addr, vaddr addr,
vaddr len, vaddr len,

View File

@ -205,15 +205,10 @@ DESIGN REQUIREMENTS:
(Current solution) (Current solution)
We have updated cputlb.c to defer operations when a cross-vCPU A new set of tlb flush operations (tlb_flush_*_all_cpus_synced) force
operation with async_run_on_cpu() which ensures each vCPU sees a synchronisation by setting the source vCPUs work as "safe work" and
coherent state when it next runs its work (in a few instructions exiting the cpu run loop. This ensures that by the time execution
time). restarts all flush operations have completed.
A new set up operations (tlb_flush_*_all_cpus) take an additional flag
which when set will force synchronisation by setting the source vCPUs
work as "safe work" and exiting the cpu run loop. This ensure by the
time execution restarts all flush operations have completed.
TLB flag updates are all done atomically and are also protected by the TLB flag updates are all done atomically and are also protected by the
corresponding page lock. corresponding page lock.

View File

@ -400,6 +400,7 @@ static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason)
machine->fdt = fdt; machine->fdt = fdt;
pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine); pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine);
pm->cpu->vhyp_class = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(pm->cpu->vhyp);
} }
enum pegasos2_rtas_tokens { enum pegasos2_rtas_tokens {
@ -984,7 +985,7 @@ static void *build_fdt(MachineState *machine, int *fdt_size)
cpu->env.icache_line_size); cpu->env.icache_line_size);
qemu_fdt_setprop_cell(fdt, cp, "i-cache-line-size", qemu_fdt_setprop_cell(fdt, cp, "i-cache-line-size",
cpu->env.icache_line_size); cpu->env.icache_line_size);
if (cpu->env.id_tlbs) { if (ppc_is_split_tlb(cpu)) {
qemu_fdt_setprop_cell(fdt, cp, "i-tlb-sets", cpu->env.nb_ways); qemu_fdt_setprop_cell(fdt, cp, "i-tlb-sets", cpu->env.nb_ways);
qemu_fdt_setprop_cell(fdt, cp, "i-tlb-size", cpu->env.tlb_per_way); qemu_fdt_setprop_cell(fdt, cp, "i-tlb-size", cpu->env.tlb_per_way);
qemu_fdt_setprop_cell(fdt, cp, "d-tlb-sets", cpu->env.nb_ways); qemu_fdt_setprop_cell(fdt, cp, "d-tlb-sets", cpu->env.nb_ways);

View File

@ -353,6 +353,32 @@ static void spapr_dt_pa_features(SpaprMachineState *spapr,
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
} }
static void spapr_dt_pi_features(SpaprMachineState *spapr,
PowerPCCPU *cpu,
void *fdt, int offset)
{
uint8_t pi_features[] = { 1, 0,
0x00 };
if (kvm_enabled() && ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
0, cpu->compat_pvr)) {
/*
* POWER9 and later CPUs with KVM run in LPAR-per-thread mode where
* all threads are essentially independent CPUs, and msgsndp does not
* work (because it is physically-addressed) and therefore is
* emulated by KVM, so disable it here to ensure XIVE will be used.
* This is both KVM and CPU implementation-specific behaviour so a KVM
* cap would be cleanest, but for now this works. If KVM ever permits
* native msgsndp execution by guests, a cap could be added at that
* time.
*/
pi_features[2] |= 0x08; /* 4: No msgsndp */
}
_FDT((fdt_setprop(fdt, offset, "ibm,pi-features", pi_features,
sizeof(pi_features))));
}
static hwaddr spapr_node0_size(MachineState *machine) static hwaddr spapr_node0_size(MachineState *machine)
{ {
if (machine->numa_state->num_nodes) { if (machine->numa_state->num_nodes) {
@ -815,6 +841,8 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
spapr_dt_pa_features(spapr, cpu, fdt, offset); spapr_dt_pa_features(spapr, cpu, fdt, offset);
spapr_dt_pi_features(spapr, cpu, fdt, offset);
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
cs->cpu_index / vcpus_per_socket))); cs->cpu_index / vcpus_per_socket)));

View File

@ -67,25 +67,16 @@ void tlb_destroy(CPUState *cpu);
* MMU indexes. * MMU indexes.
*/ */
void tlb_flush_page(CPUState *cpu, vaddr addr); void tlb_flush_page(CPUState *cpu, vaddr addr);
/**
* tlb_flush_page_all_cpus:
* @cpu: src CPU of the flush
* @addr: virtual address of page to be flushed
*
* Flush one page from the TLB of the specified CPU, for all
* MMU indexes.
*/
void tlb_flush_page_all_cpus(CPUState *src, vaddr addr);
/** /**
* tlb_flush_page_all_cpus_synced: * tlb_flush_page_all_cpus_synced:
* @cpu: src CPU of the flush * @cpu: src CPU of the flush
* @addr: virtual address of page to be flushed * @addr: virtual address of page to be flushed
* *
* Flush one page from the TLB of the specified CPU, for all MMU * Flush one page from the TLB of all CPUs, for all
* indexes like tlb_flush_page_all_cpus except the source vCPUs work * MMU indexes.
* is scheduled as safe work meaning all flushes will be complete once *
* the source vCPUs safe work is complete. This will depend on when * When this function returns, no CPUs will subsequently perform
* the guests translation ends the TB. * translations using the flushed TLBs.
*/ */
void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr); void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr);
/** /**
@ -98,19 +89,14 @@ void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr);
* use one of the other functions for efficiency. * use one of the other functions for efficiency.
*/ */
void tlb_flush(CPUState *cpu); void tlb_flush(CPUState *cpu);
/**
* tlb_flush_all_cpus:
* @cpu: src CPU of the flush
*/
void tlb_flush_all_cpus(CPUState *src_cpu);
/** /**
* tlb_flush_all_cpus_synced: * tlb_flush_all_cpus_synced:
* @cpu: src CPU of the flush * @cpu: src CPU of the flush
* *
* Like tlb_flush_all_cpus except this except the source vCPUs work is * Flush the entire TLB for all CPUs, for all MMU indexes.
* scheduled as safe work meaning all flushes will be complete once *
* the source vCPUs safe work is complete. This will depend on when * When this function returns, no CPUs will subsequently perform
* the guests translation ends the TB. * translations using the flushed TLBs.
*/ */
void tlb_flush_all_cpus_synced(CPUState *src_cpu); void tlb_flush_all_cpus_synced(CPUState *src_cpu);
/** /**
@ -125,27 +111,16 @@ void tlb_flush_all_cpus_synced(CPUState *src_cpu);
void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr,
uint16_t idxmap); uint16_t idxmap);
/** /**
* tlb_flush_page_by_mmuidx_all_cpus: * tlb_flush_page_by_mmuidx_all_cpus_synced:
* @cpu: Originating CPU of the flush * @cpu: Originating CPU of the flush
* @addr: virtual address of page to be flushed * @addr: virtual address of page to be flushed
* @idxmap: bitmap of MMU indexes to flush * @idxmap: bitmap of MMU indexes to flush
* *
* Flush one page from the TLB of all CPUs, for the specified * Flush one page from the TLB of all CPUs, for the specified
* MMU indexes. * MMU indexes.
*/
void tlb_flush_page_by_mmuidx_all_cpus(CPUState *cpu, vaddr addr,
uint16_t idxmap);
/**
* tlb_flush_page_by_mmuidx_all_cpus_synced:
* @cpu: Originating CPU of the flush
* @addr: virtual address of page to be flushed
* @idxmap: bitmap of MMU indexes to flush
* *
* Flush one page from the TLB of all CPUs, for the specified MMU * When this function returns, no CPUs will subsequently perform
* indexes like tlb_flush_page_by_mmuidx_all_cpus except the source * translations using the flushed TLBs.
* vCPUs work is scheduled as safe work meaning all flushes will be
* complete once the source vCPUs safe work is complete. This will
* depend on when the guests translation ends the TB.
*/ */
void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr, void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr,
uint16_t idxmap); uint16_t idxmap);
@ -159,25 +134,16 @@ void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr,
* MMU indexes. * MMU indexes.
*/ */
void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap); void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap);
/**
* tlb_flush_by_mmuidx_all_cpus:
* @cpu: Originating CPU of the flush
* @idxmap: bitmap of MMU indexes to flush
*
* Flush all entries from all TLBs of all CPUs, for the specified
* MMU indexes.
*/
void tlb_flush_by_mmuidx_all_cpus(CPUState *cpu, uint16_t idxmap);
/** /**
* tlb_flush_by_mmuidx_all_cpus_synced: * tlb_flush_by_mmuidx_all_cpus_synced:
* @cpu: Originating CPU of the flush * @cpu: Originating CPU of the flush
* @idxmap: bitmap of MMU indexes to flush * @idxmap: bitmap of MMU indexes to flush
* *
* Flush all entries from all TLBs of all CPUs, for the specified * Flush all entries from the TLB of all CPUs, for the specified
* MMU indexes like tlb_flush_by_mmuidx_all_cpus except except the source * MMU indexes.
* vCPUs work is scheduled as safe work meaning all flushes will be *
* complete once the source vCPUs safe work is complete. This will * When this function returns, no CPUs will subsequently perform
* depend on when the guests translation ends the TB. * translations using the flushed TLBs.
*/ */
void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, uint16_t idxmap); void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, uint16_t idxmap);
@ -194,8 +160,6 @@ void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr,
uint16_t idxmap, unsigned bits); uint16_t idxmap, unsigned bits);
/* Similarly, with broadcast and syncing. */ /* Similarly, with broadcast and syncing. */
void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu, vaddr addr,
uint16_t idxmap, unsigned bits);
void tlb_flush_page_bits_by_mmuidx_all_cpus_synced void tlb_flush_page_bits_by_mmuidx_all_cpus_synced
(CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits); (CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits);
@ -215,9 +179,6 @@ void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
unsigned bits); unsigned bits);
/* Similarly, with broadcast and syncing. */ /* Similarly, with broadcast and syncing. */
void tlb_flush_range_by_mmuidx_all_cpus(CPUState *cpu, vaddr addr,
vaddr len, uint16_t idxmap,
unsigned bits);
void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu,
vaddr addr, vaddr addr,
vaddr len, vaddr len,
@ -290,18 +251,12 @@ static inline void tlb_destroy(CPUState *cpu)
static inline void tlb_flush_page(CPUState *cpu, vaddr addr) static inline void tlb_flush_page(CPUState *cpu, vaddr addr)
{ {
} }
static inline void tlb_flush_page_all_cpus(CPUState *src, vaddr addr)
{
}
static inline void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr) static inline void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr)
{ {
} }
static inline void tlb_flush(CPUState *cpu) static inline void tlb_flush(CPUState *cpu)
{ {
} }
static inline void tlb_flush_all_cpus(CPUState *src_cpu)
{
}
static inline void tlb_flush_all_cpus_synced(CPUState *src_cpu) static inline void tlb_flush_all_cpus_synced(CPUState *src_cpu)
{ {
} }
@ -313,20 +268,11 @@ static inline void tlb_flush_page_by_mmuidx(CPUState *cpu,
static inline void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap) static inline void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap)
{ {
} }
static inline void tlb_flush_page_by_mmuidx_all_cpus(CPUState *cpu,
vaddr addr,
uint16_t idxmap)
{
}
static inline void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, static inline void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu,
vaddr addr, vaddr addr,
uint16_t idxmap) uint16_t idxmap)
{ {
} }
static inline void tlb_flush_by_mmuidx_all_cpus(CPUState *cpu, uint16_t idxmap)
{
}
static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
uint16_t idxmap) uint16_t idxmap)
{ {
@ -337,12 +283,6 @@ static inline void tlb_flush_page_bits_by_mmuidx(CPUState *cpu,
unsigned bits) unsigned bits)
{ {
} }
static inline void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu,
vaddr addr,
uint16_t idxmap,
unsigned bits)
{
}
static inline void static inline void
tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr, tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr,
uint16_t idxmap, unsigned bits) uint16_t idxmap, unsigned bits)
@ -353,13 +293,6 @@ static inline void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
unsigned bits) unsigned bits)
{ {
} }
static inline void tlb_flush_range_by_mmuidx_all_cpus(CPUState *cpu,
vaddr addr,
vaddr len,
uint16_t idxmap,
unsigned bits)
{
}
static inline void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, static inline void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu,
vaddr addr, vaddr addr,
vaddr len, vaddr len,

View File

@ -533,6 +533,9 @@ FIELD(MSR, LE, MSR_LE, 1)
#define MMCR0_FC56 PPC_BIT(59) /* PMC Freeze Counters 5-6 bit */ #define MMCR0_FC56 PPC_BIT(59) /* PMC Freeze Counters 5-6 bit */
#define MMCR0_PMC1CE PPC_BIT(48) /* MMCR0 PMC1 Condition Enabled */ #define MMCR0_PMC1CE PPC_BIT(48) /* MMCR0 PMC1 Condition Enabled */
#define MMCR0_PMCjCE PPC_BIT(49) /* MMCR0 PMCj Condition Enabled */ #define MMCR0_PMCjCE PPC_BIT(49) /* MMCR0 PMCj Condition Enabled */
#define MMCR0_FCP PPC_BIT(34) /* Freeze Counters/BHRB if PR=1 */
#define MMCR0_FCPC PPC_BIT(51) /* Condition for FCP bit */
#define MMCR0_BHRBA_NR PPC_BIT_NR(42) /* BHRB Available */
/* MMCR0 userspace r/w mask */ /* MMCR0 userspace r/w mask */
#define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE) #define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
/* MMCR2 userspace r/w mask */ /* MMCR2 userspace r/w mask */
@ -545,6 +548,10 @@ FIELD(MSR, LE, MSR_LE, 1)
#define MMCR2_UREG_MASK (MMCR2_FC1P0 | MMCR2_FC2P0 | MMCR2_FC3P0 | \ #define MMCR2_UREG_MASK (MMCR2_FC1P0 | MMCR2_FC2P0 | MMCR2_FC3P0 | \
MMCR2_FC4P0 | MMCR2_FC5P0 | MMCR2_FC6P0) MMCR2_FC4P0 | MMCR2_FC5P0 | MMCR2_FC6P0)
#define MMCRA_BHRBRD PPC_BIT(26) /* BHRB Recording Disable */
#define MMCRA_IFM_MASK PPC_BITMASK(32, 33) /* BHRB Instruction Filtering */
#define MMCRA_IFM_SHIFT PPC_BIT_NR(33)
#define MMCR1_EVT_SIZE 8 #define MMCR1_EVT_SIZE 8
/* extract64() does a right shift before extracting */ /* extract64() does a right shift before extracting */
#define MMCR1_PMC1SEL_START 32 #define MMCR1_PMC1SEL_START 32
@ -628,6 +635,7 @@ FIELD(MSR, LE, MSR_LE, 1)
/* HFSCR bits */ /* HFSCR bits */
#define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */ #define HFSCR_MSGP PPC_BIT(53) /* Privileged Message Send Facilities */
#define HFSCR_BHRB PPC_BIT(59) /* BHRB Instructions */
#define HFSCR_IC_MSGP 0xA #define HFSCR_IC_MSGP 0xA
#define DBCR0_ICMP (1 << 27) #define DBCR0_ICMP (1 << 27)
@ -770,6 +778,8 @@ enum {
POWERPC_FLAG_SMT = 0x00400000, POWERPC_FLAG_SMT = 0x00400000,
/* Using "LPAR per core" mode (as opposed to per-thread) */ /* Using "LPAR per core" mode (as opposed to per-thread) */
POWERPC_FLAG_SMT_1LPAR = 0x00800000, POWERPC_FLAG_SMT_1LPAR = 0x00800000,
/* Has BHRB */
POWERPC_FLAG_BHRB = 0x01000000,
}; };
/* /*
@ -797,6 +807,7 @@ enum {
HFLAGS_PMCJCE = 17, /* MMCR0 PMCjCE bit */ HFLAGS_PMCJCE = 17, /* MMCR0 PMCjCE bit */
HFLAGS_PMC_OTHER = 18, /* PMC other than PMC5-6 is enabled */ HFLAGS_PMC_OTHER = 18, /* PMC other than PMC5-6 is enabled */
HFLAGS_INSN_CNT = 19, /* PMU instruction count enabled */ HFLAGS_INSN_CNT = 19, /* PMU instruction count enabled */
HFLAGS_BHRB_ENABLE = 20, /* Summary flag for enabling BHRB */
HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */ HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */
HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */ HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */
@ -1152,7 +1163,11 @@ FIELD(FPSCR, FI, FPSCR_FI, 1)
#define DBELL_TYPE_DBELL_SERVER (0x05 << DBELL_TYPE_SHIFT) #define DBELL_TYPE_DBELL_SERVER (0x05 << DBELL_TYPE_SHIFT)
#define DBELL_BRDCAST PPC_BIT(37) #define DBELL_BRDCAST_MASK PPC_BITMASK(37, 38)
#define DBELL_BRDCAST_SHIFT 25
#define DBELL_BRDCAST_SUBPROC (0x1 << DBELL_BRDCAST_SHIFT)
#define DBELL_BRDCAST_CORE (0x2 << DBELL_BRDCAST_SHIFT)
#define DBELL_LPIDTAG_SHIFT 14 #define DBELL_LPIDTAG_SHIFT 14
#define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT) #define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT)
#define DBELL_PIRTAG_MASK 0x3fff #define DBELL_PIRTAG_MASK 0x3fff
@ -1210,6 +1225,9 @@ struct pnv_tod_tbst {
#define PPC_CPU_OPCODES_LEN 0x40 #define PPC_CPU_OPCODES_LEN 0x40
#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20
#define BHRB_MAX_NUM_ENTRIES_LOG2 (5)
#define BHRB_MAX_NUM_ENTRIES (1 << BHRB_MAX_NUM_ENTRIES_LOG2)
struct CPUArchState { struct CPUArchState {
/* Most commonly used resources during translated code execution first */ /* Most commonly used resources during translated code execution first */
target_ulong gpr[32]; /* general purpose registers */ target_ulong gpr[32]; /* general purpose registers */
@ -1250,6 +1268,9 @@ struct CPUArchState {
ppc_slb_t slb[MAX_SLB_ENTRIES]; /* PowerPC 64 SLB area */ ppc_slb_t slb[MAX_SLB_ENTRIES]; /* PowerPC 64 SLB area */
struct CPUBreakpoint *ciabr_breakpoint; struct CPUBreakpoint *ciabr_breakpoint;
struct CPUWatchpoint *dawr0_watchpoint; struct CPUWatchpoint *dawr0_watchpoint;
/* POWER CPU regs/state */
target_ulong scratch[8]; /* SCRATCH registers (shared across core) */
#endif #endif
target_ulong sr[32]; /* segment registers */ target_ulong sr[32]; /* segment registers */
uint32_t nb_BATs; /* number of BATs */ uint32_t nb_BATs; /* number of BATs */
@ -1260,7 +1281,6 @@ struct CPUArchState {
int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
int nb_ways; /* Number of ways in the TLB set */ int nb_ways; /* Number of ways in the TLB set */
int last_way; /* Last used way used to allocate TLB in a LRU way */ int last_way; /* Last used way used to allocate TLB in a LRU way */
int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */
int nb_pids; /* Number of available PID registers */ int nb_pids; /* Number of available PID registers */
int tlb_type; /* Type of TLB we're dealing with */ int tlb_type; /* Type of TLB we're dealing with */
ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */ ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */
@ -1306,6 +1326,16 @@ struct CPUArchState {
int dcache_line_size; int dcache_line_size;
int icache_line_size; int icache_line_size;
#ifdef TARGET_PPC64
/* Branch History Rolling Buffer (BHRB) resources */
target_ulong bhrb_num_entries;
intptr_t bhrb_base;
target_ulong bhrb_filter;
target_ulong bhrb_offset;
target_ulong bhrb_offset_mask;
uint64_t bhrb[BHRB_MAX_NUM_ENTRIES];
#endif
/* These resources are used during exception processing */ /* These resources are used during exception processing */
/* CPU model definition */ /* CPU model definition */
target_ulong msr_mask; target_ulong msr_mask;
@ -1351,6 +1381,9 @@ struct CPUArchState {
/* Power management */ /* Power management */
int (*check_pow)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env);
/* attn instruction enable */
int (*check_attn)(CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void *load_info; /* holds boot loading state */ void *load_info; /* holds boot loading state */
#endif #endif
@ -1435,6 +1468,7 @@ struct ArchCPU {
int vcpu_id; int vcpu_id;
uint32_t compat_pvr; uint32_t compat_pvr;
PPCVirtualHypervisor *vhyp; PPCVirtualHypervisor *vhyp;
PPCVirtualHypervisorClass *vhyp_class;
void *machine_data; void *machine_data;
int32_t node_id; /* NUMA node this CPU belongs to */ int32_t node_id; /* NUMA node this CPU belongs to */
PPCHash64Options *hash64_opts; PPCHash64Options *hash64_opts;
@ -1498,6 +1532,7 @@ struct PowerPCCPUClass {
int n_host_threads; int n_host_threads;
void (*init_proc)(CPUPPCState *env); void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env);
int (*check_attn)(CPUPPCState *env);
}; };
ObjectClass *ppc_cpu_class_by_name(const char *name); ObjectClass *ppc_cpu_class_by_name(const char *name);
@ -1532,7 +1567,7 @@ DECLARE_OBJ_CHECKERS(PPCVirtualHypervisor, PPCVirtualHypervisorClass,
static inline bool vhyp_cpu_in_nested(PowerPCCPU *cpu) static inline bool vhyp_cpu_in_nested(PowerPCCPU *cpu)
{ {
return PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp)->cpu_in_nested(cpu); return cpu->vhyp_class->cpu_in_nested(cpu);
} }
#endif /* CONFIG_USER_ONLY */ #endif /* CONFIG_USER_ONLY */
@ -1607,10 +1642,6 @@ void ppc_tlb_invalidate_all(CPUPPCState *env);
void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr); void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr);
void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp); void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
void cpu_ppc_set_1lpar(PowerPCCPU *cpu); void cpu_ppc_set_1lpar(PowerPCCPU *cpu);
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
target_ulong address, uint32_t pid);
int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid);
hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb);
#endif #endif
void ppc_store_fpscr(CPUPPCState *env, target_ulong val); void ppc_store_fpscr(CPUPPCState *env, target_ulong val);
@ -1777,9 +1808,9 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_SPRG2 (0x112) #define SPR_SPRG2 (0x112)
#define SPR_SPRG3 (0x113) #define SPR_SPRG3 (0x113)
#define SPR_SPRG4 (0x114) #define SPR_SPRG4 (0x114)
#define SPR_SCOMC (0x114) #define SPR_POWER_SPRC (0x114)
#define SPR_SPRG5 (0x115) #define SPR_SPRG5 (0x115)
#define SPR_SCOMD (0x115) #define SPR_POWER_SPRD (0x115)
#define SPR_SPRG6 (0x116) #define SPR_SPRG6 (0x116)
#define SPR_SPRG7 (0x117) #define SPR_SPRG7 (0x117)
#define SPR_ASR (0x118) #define SPR_ASR (0x118)
@ -2069,6 +2100,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_DEXCR (0x33C) #define SPR_DEXCR (0x33C)
#define SPR_IC (0x350) #define SPR_IC (0x350)
#define SPR_VTB (0x351) #define SPR_VTB (0x351)
#define SPR_LDBAR (0x352)
#define SPR_MMCRC (0x353) #define SPR_MMCRC (0x353)
#define SPR_PSSCR (0x357) #define SPR_PSSCR (0x357)
#define SPR_440_INV0 (0x370) #define SPR_440_INV0 (0x370)
@ -2091,6 +2123,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_POWER_MMCRS (0x37E) #define SPR_POWER_MMCRS (0x37E)
#define SPR_WORT (0x37F) #define SPR_WORT (0x37F)
#define SPR_PPR (0x380) #define SPR_PPR (0x380)
#define SPR_PPR32 (0x382)
#define SPR_750_GQR0 (0x390) #define SPR_750_GQR0 (0x390)
#define SPR_440_DNV0 (0x390) #define SPR_440_DNV0 (0x390)
#define SPR_750_GQR1 (0x391) #define SPR_750_GQR1 (0x391)
@ -2114,6 +2147,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_440_IVLIM (0x399) #define SPR_440_IVLIM (0x399)
#define SPR_TSCR (0x399) #define SPR_TSCR (0x399)
#define SPR_750_DMAU (0x39A) #define SPR_750_DMAU (0x39A)
#define SPR_POWER_TTR (0x39A)
#define SPR_750_DMAL (0x39B) #define SPR_750_DMAL (0x39B)
#define SPR_440_RSTCFG (0x39B) #define SPR_440_RSTCFG (0x39B)
#define SPR_BOOKE_DCDBTRL (0x39C) #define SPR_BOOKE_DCDBTRL (0x39C)
@ -2295,6 +2329,8 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define HID0_NAP (1 << 22) /* pre-2.06 */ #define HID0_NAP (1 << 22) /* pre-2.06 */
#define HID0_HILE PPC_BIT(19) /* POWER8 */ #define HID0_HILE PPC_BIT(19) /* POWER8 */
#define HID0_POWER9_HILE PPC_BIT(4) #define HID0_POWER9_HILE PPC_BIT(4)
#define HID0_ENABLE_ATTN PPC_BIT(31) /* POWER8 */
#define HID0_POWER9_ENABLE_ATTN PPC_BIT(3)
/*****************************************************************************/ /*****************************************************************************/
/* PowerPC Instructions types definitions */ /* PowerPC Instructions types definitions */
@ -2856,6 +2892,10 @@ static inline void booke206_fixed_size_tlbn(CPUPPCState *env, const int tlbn,
tlb->mas1 |= ((uint32_t)tsize) << MAS1_TSIZE_SHIFT; tlb->mas1 |= ((uint32_t)tsize) << MAS1_TSIZE_SHIFT;
} }
static inline bool ppc_is_split_tlb(PowerPCCPU *cpu)
{
return cpu->env.tlb_type == TLB_6XX;
}
#endif #endif
static inline bool msr_is_64bit(CPUPPCState *env, target_ulong msr) static inline bool msr_is_64bit(CPUPPCState *env, target_ulong msr)
@ -3000,6 +3040,12 @@ static inline int check_pow_nocheck(CPUPPCState *env)
return 1; return 1;
} }
/* attn enable check */
static inline int check_attn_none(CPUPPCState *env)
{
return 0;
}
/*****************************************************************************/ /*****************************************************************************/
/* PowerPC implementations definitions */ /* PowerPC implementations definitions */

View File

@ -246,7 +246,7 @@ static void register_amr_sprs(CPUPPCState *env)
spr_register_hv(env, SPR_AMOR, "AMOR", spr_register_hv(env, SPR_AMOR, "AMOR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_core_lpar_write_generic,
0); 0);
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
} }
@ -792,7 +792,7 @@ static void register_BookE_sprs(CPUPPCState *env, uint64_t ivor_mask)
0x00000000); 0x00000000);
spr_register(env, SPR_BOOKE_DECAR, "DECAR", spr_register(env, SPR_BOOKE_DECAR, "DECAR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, &spr_write_generic, SPR_NOACCESS, &spr_write_generic32,
0x00000000); 0x00000000);
/* SPRGs */ /* SPRGs */
spr_register(env, SPR_USPRG0, "USPRG0", spr_register(env, SPR_USPRG0, "USPRG0",
@ -2107,19 +2107,42 @@ static int check_pow_hid0_74xx(CPUPPCState *env)
return 0; return 0;
} }
#if defined(TARGET_PPC64)
static int check_attn_hid0(CPUPPCState *env)
{
if (env->spr[SPR_HID0] & HID0_ENABLE_ATTN) {
return 1;
}
return 0;
}
static int check_attn_hid0_power9(CPUPPCState *env)
{
if (env->spr[SPR_HID0] & HID0_POWER9_ENABLE_ATTN) {
return 1;
}
return 0;
}
#endif
static void init_tlbs_emb(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
env->nb_tlb = 64;
env->nb_ways = 1;
env->tlb_type = TLB_EMB;
#endif
}
static void init_proc_405(CPUPPCState *env) static void init_proc_405(CPUPPCState *env)
{ {
register_40x_sprs(env); register_40x_sprs(env);
register_405_sprs(env); register_405_sprs(env);
register_usprgh_sprs(env); register_usprgh_sprs(env);
/* Memory management */ init_tlbs_emb(env);
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
env->tlb_type = TLB_EMB;
#endif
init_excp_4xx(env); init_excp_4xx(env);
env->dcache_line_size = 32; env->dcache_line_size = 32;
env->icache_line_size = 32; env->icache_line_size = 32;
@ -2138,6 +2161,7 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 405"; dc->desc = "PowerPC 405";
pcc->init_proc = init_proc_405; pcc->init_proc = init_proc_405;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_DCR | PPC_WRTEE | PPC_DCR | PPC_WRTEE |
PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |
@ -2186,13 +2210,8 @@ static void init_proc_440EP(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
/* Memory management */
#if !defined(CONFIG_USER_ONLY) init_tlbs_emb(env);
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env); init_excp_BookE(env);
env->dcache_line_size = 32; env->dcache_line_size = 32;
env->icache_line_size = 32; env->icache_line_size = 32;
@ -2210,6 +2229,7 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 440 EP"; dc->desc = "PowerPC 440 EP";
pcc->init_proc = init_proc_440EP; pcc->init_proc = init_proc_440EP;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -2248,6 +2268,7 @@ POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 460 EX"; dc->desc = "PowerPC 460 EX";
pcc->init_proc = init_proc_440EP; pcc->init_proc = init_proc_440EP;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -2284,13 +2305,7 @@ static void init_proc_440GP(CPUPPCState *env)
register_440_sprs(env); register_440_sprs(env);
register_usprgh_sprs(env); register_usprgh_sprs(env);
/* Memory management */ init_tlbs_emb(env);
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env); init_excp_BookE(env);
env->dcache_line_size = 32; env->dcache_line_size = 32;
env->icache_line_size = 32; env->icache_line_size = 32;
@ -2308,6 +2323,7 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 440 GP"; dc->desc = "PowerPC 440 GP";
pcc->init_proc = init_proc_440GP; pcc->init_proc = init_proc_440GP;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI | PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE | PPC_CACHE_ICBI |
@ -2358,13 +2374,8 @@ static void init_proc_440x5(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
/* Memory management */
#if !defined(CONFIG_USER_ONLY) init_tlbs_emb(env);
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env); init_excp_BookE(env);
env->dcache_line_size = 32; env->dcache_line_size = 32;
env->icache_line_size = 32; env->icache_line_size = 32;
@ -2382,6 +2393,7 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 440x5"; dc->desc = "PowerPC 440x5";
pcc->init_proc = init_proc_440x5; pcc->init_proc = init_proc_440x5;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_DCR | PPC_WRTEE | PPC_RFMCI | PPC_DCR | PPC_WRTEE | PPC_RFMCI |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE | PPC_CACHE_ICBI |
@ -2417,6 +2429,7 @@ POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 440x5 with double precision FPU"; dc->desc = "PowerPC 440x5 with double precision FPU";
pcc->init_proc = init_proc_440x5; pcc->init_proc = init_proc_440x5;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT | PPC_FLOAT_FSQRT |
PPC_FLOAT_STFIWX | PPC_FLOAT_STFIWX |
@ -2465,6 +2478,7 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data)
dc->desc = "Freescale 5xx cores (aka RCPU)"; dc->desc = "Freescale 5xx cores (aka RCPU)";
pcc->init_proc = init_proc_MPC5xx; pcc->init_proc = init_proc_MPC5xx;
pcc->check_pow = check_pow_none; pcc->check_pow = check_pow_none;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_SYNC |
PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX |
@ -2507,6 +2521,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
dc->desc = "Freescale 8xx cores (aka PowerQUICC)"; dc->desc = "Freescale 8xx cores (aka PowerQUICC)";
pcc->init_proc = init_proc_MPC8xx; pcc->init_proc = init_proc_MPC8xx;
pcc->check_pow = check_pow_none; pcc->check_pow = check_pow_none;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_SYNC |
PPC_CACHE_ICBI | PPC_MFTB; PPC_CACHE_ICBI | PPC_MFTB;
@ -2557,6 +2572,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
dc->desc = "PowerPC G2"; dc->desc = "PowerPC G2";
pcc->init_proc = init_proc_G2; pcc->init_proc = init_proc_G2;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_STFIWX | PPC_FLOAT_STFIWX |
@ -2595,6 +2611,7 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data)
dc->desc = "PowerPC G2LE"; dc->desc = "PowerPC G2LE";
pcc->init_proc = init_proc_G2; pcc->init_proc = init_proc_G2;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_STFIWX | PPC_FLOAT_STFIWX |
@ -2721,12 +2738,8 @@ static void init_proc_e200(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 64; init_tlbs_emb(env);
env->nb_ways = 1;
env->id_tlbs = 0;
env->tlb_type = TLB_EMB;
#endif
init_excp_e200(env, 0xFFFF0000UL); init_excp_e200(env, 0xFFFF0000UL);
env->dcache_line_size = 32; env->dcache_line_size = 32;
env->icache_line_size = 32; env->icache_line_size = 32;
@ -2741,6 +2754,7 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
dc->desc = "e200 core"; dc->desc = "e200 core";
pcc->init_proc = init_proc_e200; pcc->init_proc = init_proc_e200;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
/* /*
* XXX: unimplemented instructions: * XXX: unimplemented instructions:
* dcblc * dcblc
@ -2843,7 +2857,6 @@ static void init_proc_e500(CPUPPCState *env, int version)
/* Memory management */ /* Memory management */
env->nb_pids = 3; env->nb_pids = 3;
env->nb_ways = 2; env->nb_ways = 2;
env->id_tlbs = 0;
switch (version) { switch (version) {
case fsl_e500v1: case fsl_e500v1:
tlbncfg[0] = register_tlbncfg(2, 1, 1, 0, 256); tlbncfg[0] = register_tlbncfg(2, 1, 1, 0, 256);
@ -3029,6 +3042,7 @@ POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data)
dc->desc = "e500v1 core"; dc->desc = "e500v1 core";
pcc->init_proc = init_proc_e500v1; pcc->init_proc = init_proc_e500v1;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
PPC_SPE | PPC_SPE_SINGLE | PPC_SPE | PPC_SPE_SINGLE |
PPC_WRTEE | PPC_RFDI | PPC_WRTEE | PPC_RFDI |
@ -3072,6 +3086,7 @@ POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data)
dc->desc = "e500v2 core"; dc->desc = "e500v2 core";
pcc->init_proc = init_proc_e500v2; pcc->init_proc = init_proc_e500v2;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE | PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE |
PPC_WRTEE | PPC_RFDI | PPC_WRTEE | PPC_RFDI |
@ -3115,6 +3130,7 @@ POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data)
dc->desc = "e500mc core"; dc->desc = "e500mc core";
pcc->init_proc = init_proc_e500mc; pcc->init_proc = init_proc_e500mc;
pcc->check_pow = check_pow_none; pcc->check_pow = check_pow_none;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
PPC_WRTEE | PPC_RFDI | PPC_RFMCI | PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
@ -3161,6 +3177,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
dc->desc = "e5500 core"; dc->desc = "e5500 core";
pcc->init_proc = init_proc_e5500; pcc->init_proc = init_proc_e5500;
pcc->check_pow = check_pow_none; pcc->check_pow = check_pow_none;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
PPC_WRTEE | PPC_RFDI | PPC_RFMCI | PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
@ -3209,6 +3226,7 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data)
dc->desc = "e6500 core"; dc->desc = "e6500 core";
pcc->init_proc = init_proc_e6500; pcc->init_proc = init_proc_e6500;
pcc->check_pow = check_pow_none; pcc->check_pow = check_pow_none;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
PPC_WRTEE | PPC_RFDI | PPC_RFMCI | PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
@ -3271,6 +3289,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 603"; dc->desc = "PowerPC 603";
pcc->init_proc = init_proc_603; pcc->init_proc = init_proc_603;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3310,6 +3329,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 603e"; dc->desc = "PowerPC 603e";
pcc->init_proc = init_proc_603; pcc->init_proc = init_proc_603;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3355,6 +3375,7 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data)
dc->desc = "e300 core"; dc->desc = "e300 core";
pcc->init_proc = init_proc_e300; pcc->init_proc = init_proc_e300;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_STFIWX | PPC_FLOAT_STFIWX |
@ -3410,6 +3431,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 604"; dc->desc = "PowerPC 604";
pcc->init_proc = init_proc_604; pcc->init_proc = init_proc_604;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3455,6 +3477,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 604E"; dc->desc = "PowerPC 604E";
pcc->init_proc = init_proc_604E; pcc->init_proc = init_proc_604E;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3511,6 +3534,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 740"; dc->desc = "PowerPC 740";
pcc->init_proc = init_proc_740; pcc->init_proc = init_proc_740;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3576,6 +3600,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 750"; dc->desc = "PowerPC 750";
pcc->init_proc = init_proc_750; pcc->init_proc = init_proc_750;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3722,6 +3747,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 750 CL"; dc->desc = "PowerPC 750 CL";
pcc->init_proc = init_proc_750cl; pcc->init_proc = init_proc_750cl;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
/* /*
* XXX: not implemented: * XXX: not implemented:
* cache lock instructions: * cache lock instructions:
@ -3829,6 +3855,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 750CX"; dc->desc = "PowerPC 750CX";
pcc->init_proc = init_proc_750cx; pcc->init_proc = init_proc_750cx;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3901,6 +3928,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 750FX"; dc->desc = "PowerPC 750FX";
pcc->init_proc = init_proc_750fx; pcc->init_proc = init_proc_750fx;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -3973,6 +4001,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 750GX"; dc->desc = "PowerPC 750GX";
pcc->init_proc = init_proc_750gx; pcc->init_proc = init_proc_750gx;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -4032,6 +4061,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 745"; dc->desc = "PowerPC 745";
pcc->init_proc = init_proc_745; pcc->init_proc = init_proc_745;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -4077,6 +4107,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 755"; dc->desc = "PowerPC 755";
pcc->init_proc = init_proc_755; pcc->init_proc = init_proc_755;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@ -4143,6 +4174,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7400 (aka G4)"; dc->desc = "PowerPC 7400 (aka G4)";
pcc->init_proc = init_proc_7400; pcc->init_proc = init_proc_7400;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4222,6 +4254,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7410 (aka G4)"; dc->desc = "PowerPC 7410 (aka G4)";
pcc->init_proc = init_proc_7410; pcc->init_proc = init_proc_7410;
pcc->check_pow = check_pow_hid0; pcc->check_pow = check_pow_hid0;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4322,6 +4355,7 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7440 (aka G4)"; dc->desc = "PowerPC 7440 (aka G4)";
pcc->init_proc = init_proc_7440; pcc->init_proc = init_proc_7440;
pcc->check_pow = check_pow_hid0_74xx; pcc->check_pow = check_pow_hid0_74xx;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4444,6 +4478,7 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7450 (aka G4)"; dc->desc = "PowerPC 7450 (aka G4)";
pcc->init_proc = init_proc_7450; pcc->init_proc = init_proc_7450;
pcc->check_pow = check_pow_hid0_74xx; pcc->check_pow = check_pow_hid0_74xx;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4573,6 +4608,7 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7445 (aka G4)"; dc->desc = "PowerPC 7445 (aka G4)";
pcc->init_proc = init_proc_7445; pcc->init_proc = init_proc_7445;
pcc->check_pow = check_pow_hid0_74xx; pcc->check_pow = check_pow_hid0_74xx;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4704,6 +4740,7 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7455 (aka G4)"; dc->desc = "PowerPC 7455 (aka G4)";
pcc->init_proc = init_proc_7455; pcc->init_proc = init_proc_7455;
pcc->check_pow = check_pow_hid0_74xx; pcc->check_pow = check_pow_hid0_74xx;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4855,6 +4892,7 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 7457 (aka G4)"; dc->desc = "PowerPC 7457 (aka G4)";
pcc->init_proc = init_proc_7457; pcc->init_proc = init_proc_7457;
pcc->check_pow = check_pow_hid0_74xx; pcc->check_pow = check_pow_hid0_74xx;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -4989,6 +5027,7 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
dc->desc = "PowerPC e600"; dc->desc = "PowerPC e600";
pcc->init_proc = init_proc_e600; pcc->init_proc = init_proc_e600;
pcc->check_pow = check_pow_hid0_74xx; pcc->check_pow = check_pow_hid0_74xx;
pcc->check_attn = check_attn_none;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -5152,7 +5191,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
KVM_REG_PPC_MMCR1, 0x00000000); KVM_REG_PPC_MMCR1, 0x00000000);
spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA", spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_MMCRA,
KVM_REG_PPC_MMCRA, 0x00000000); KVM_REG_PPC_MMCRA, 0x00000000);
spr_register_kvm(env, SPR_POWER_PMC1, "PMC1", spr_register_kvm(env, SPR_POWER_PMC1, "PMC1",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -5415,7 +5454,7 @@ static void register_book3s_ids_sprs(CPUPPCState *env)
spr_register_hv(env, SPR_MMCRC, "MMCRC", spr_register_hv(env, SPR_MMCRC, "MMCRC",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic32, &spr_read_generic, &spr_core_write_generic32,
0x00000000); 0x00000000);
spr_register_hv(env, SPR_MMCRH, "MMCRH", spr_register_hv(env, SPR_MMCRH, "MMCRH",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -5455,7 +5494,7 @@ static void register_book3s_ids_sprs(CPUPPCState *env)
spr_register_hv(env, SPR_HRMOR, "HRMOR", spr_register_hv(env, SPR_HRMOR, "HRMOR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_core_write_generic,
0x00000000); 0x00000000);
} }
@ -5549,6 +5588,14 @@ static void register_HEIR64_spr(CPUPPCState *env)
0x00000000); 0x00000000);
} }
static void register_power7_common_sprs(CPUPPCState *env)
{
spr_register(env, SPR_PPR32, "PPR32",
&spr_read_ppr32, &spr_write_ppr32,
&spr_read_ppr32, &spr_write_ppr32,
0x00000000);
}
static void register_power8_tce_address_control_sprs(CPUPPCState *env) static void register_power8_tce_address_control_sprs(CPUPPCState *env)
{ {
spr_register_kvm(env, SPR_TAR, "TAR", spr_register_kvm(env, SPR_TAR, "TAR",
@ -5675,7 +5722,7 @@ static void register_power_common_book4_sprs(CPUPPCState *env)
spr_register_hv(env, SPR_TSCR, "TSCR", spr_register_hv(env, SPR_TSCR, "TSCR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic32, &spr_read_generic, &spr_core_write_generic32,
0x00000000); 0x00000000);
spr_register_hv(env, SPR_HMER, "HMER", spr_register_hv(env, SPR_HMER, "HMER",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -5685,7 +5732,7 @@ static void register_power_common_book4_sprs(CPUPPCState *env)
spr_register_hv(env, SPR_HMEER, "HMEER", spr_register_hv(env, SPR_HMEER, "HMEER",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_core_write_generic,
0x00000000); 0x00000000);
spr_register_hv(env, SPR_TFMR, "TFMR", spr_register_hv(env, SPR_TFMR, "TFMR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -5702,6 +5749,26 @@ static void register_power_common_book4_sprs(CPUPPCState *env)
&spr_access_nop, &spr_write_generic, &spr_access_nop, &spr_write_generic,
&spr_access_nop, &spr_write_generic, &spr_access_nop, &spr_write_generic,
0x00000000); 0x00000000);
spr_register_hv(env, SPR_LDBAR, "LDBAR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_core_lpar_write_generic,
0x00000000);
spr_register_hv(env, SPR_POWER_TTR, "TTR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_core_write_generic,
0x00000000);
spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_sprc,
0x00000000);
spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_sprd, &spr_write_sprd,
0x00000000);
#endif #endif
} }
@ -5761,7 +5828,7 @@ static void register_power8_rpr_sprs(CPUPPCState *env)
spr_register_hv(env, SPR_RPR, "RPR", spr_register_hv(env, SPR_RPR, "RPR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_core_write_generic,
0x00000103070F1F3F); 0x00000103070F1F3F);
#endif #endif
} }
@ -5904,6 +5971,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
dc->desc = "PowerPC 970"; dc->desc = "PowerPC 970";
pcc->init_proc = init_proc_970; pcc->init_proc = init_proc_970;
pcc->check_pow = check_pow_970; pcc->check_pow = check_pow_970;
pcc->check_attn = check_attn_hid0;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -5979,6 +6047,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
dc->desc = "POWER5+"; dc->desc = "POWER5+";
pcc->init_proc = init_proc_power5plus; pcc->init_proc = init_proc_power5plus;
pcc->check_pow = check_pow_970; pcc->check_pow = check_pow_970;
pcc->check_attn = check_attn_hid0;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -6042,6 +6111,7 @@ static void init_proc_POWER7(CPUPPCState *env)
register_power6_common_sprs(env); register_power6_common_sprs(env);
register_HEIR32_spr(env); register_HEIR32_spr(env);
register_power6_dbg_sprs(env); register_power6_dbg_sprs(env);
register_power7_common_sprs(env);
register_power7_book4_sprs(env); register_power7_book4_sprs(env);
/* env variables */ /* env variables */
@ -6086,6 +6156,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER7; pcc->init_proc = init_proc_POWER7;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_hid0;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -6142,6 +6213,28 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x8000; pcc->l1_icache_size = 0x8000;
} }
static void bhrb_init_state(CPUPPCState *env, target_long num_entries_log2)
{
if (env->flags & POWERPC_FLAG_BHRB) {
if (num_entries_log2 > BHRB_MAX_NUM_ENTRIES_LOG2) {
num_entries_log2 = BHRB_MAX_NUM_ENTRIES_LOG2;
}
env->bhrb_num_entries = 1 << num_entries_log2;
env->bhrb_base = (intptr_t)&env->bhrb[0];
env->bhrb_offset_mask = (env->bhrb_num_entries * sizeof(uint64_t)) - 1;
}
}
static void bhrb_reset_state(CPUPPCState *env)
{
if (env->flags & POWERPC_FLAG_BHRB) {
env->bhrb_offset = 0;
env->bhrb_filter = 0;
memset(env->bhrb, 0, sizeof(env->bhrb));
}
}
#define POWER8_BHRB_ENTRIES_LOG2 5
static void init_proc_POWER8(CPUPPCState *env) static void init_proc_POWER8(CPUPPCState *env)
{ {
/* Common Registers */ /* Common Registers */
@ -6165,6 +6258,7 @@ static void init_proc_POWER8(CPUPPCState *env)
register_power6_common_sprs(env); register_power6_common_sprs(env);
register_HEIR32_spr(env); register_HEIR32_spr(env);
register_power6_dbg_sprs(env); register_power6_dbg_sprs(env);
register_power7_common_sprs(env);
register_power8_tce_address_control_sprs(env); register_power8_tce_address_control_sprs(env);
register_power8_ids_sprs(env); register_power8_ids_sprs(env);
register_power8_ebb_sprs(env); register_power8_ebb_sprs(env);
@ -6183,6 +6277,8 @@ static void init_proc_POWER8(CPUPPCState *env)
env->dcache_line_size = 128; env->dcache_line_size = 128;
env->icache_line_size = 128; env->icache_line_size = 128;
bhrb_init_state(env, POWER8_BHRB_ENTRIES_LOG2);
/* Allocate hardware IRQ controller */ /* Allocate hardware IRQ controller */
init_excp_POWER8(env); init_excp_POWER8(env);
ppcPOWER7_irq_init(env_archcpu(env)); ppcPOWER7_irq_init(env_archcpu(env));
@ -6223,6 +6319,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER8; pcc->init_proc = init_proc_POWER8;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_hid0;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -6307,6 +6404,7 @@ static struct ppc_radix_page_info POWER9_radix_page_info = {
}; };
#endif /* CONFIG_USER_ONLY */ #endif /* CONFIG_USER_ONLY */
#define POWER9_BHRB_ENTRIES_LOG2 5
static void init_proc_POWER9(CPUPPCState *env) static void init_proc_POWER9(CPUPPCState *env)
{ {
/* Common Registers */ /* Common Registers */
@ -6328,6 +6426,7 @@ static void init_proc_POWER9(CPUPPCState *env)
register_power6_common_sprs(env); register_power6_common_sprs(env);
register_HEIR32_spr(env); register_HEIR32_spr(env);
register_power6_dbg_sprs(env); register_power6_dbg_sprs(env);
register_power7_common_sprs(env);
register_power8_tce_address_control_sprs(env); register_power8_tce_address_control_sprs(env);
register_power8_ids_sprs(env); register_power8_ids_sprs(env);
register_power8_ebb_sprs(env); register_power8_ebb_sprs(env);
@ -6357,6 +6456,8 @@ static void init_proc_POWER9(CPUPPCState *env)
env->dcache_line_size = 128; env->dcache_line_size = 128;
env->icache_line_size = 128; env->icache_line_size = 128;
bhrb_init_state(env, POWER9_BHRB_ENTRIES_LOG2);
/* Allocate hardware IRQ controller */ /* Allocate hardware IRQ controller */
init_excp_POWER9(env); init_excp_POWER9(env);
ppcPOWER9_irq_init(env_archcpu(env)); ppcPOWER9_irq_init(env_archcpu(env));
@ -6412,6 +6513,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PCR_COMPAT_2_05; PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER9; pcc->init_proc = init_proc_POWER9;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_hid0_power9;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -6497,6 +6599,7 @@ static struct ppc_radix_page_info POWER10_radix_page_info = {
}; };
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
#define POWER10_BHRB_ENTRIES_LOG2 5
static void init_proc_POWER10(CPUPPCState *env) static void init_proc_POWER10(CPUPPCState *env)
{ {
/* Common Registers */ /* Common Registers */
@ -6518,6 +6621,7 @@ static void init_proc_POWER10(CPUPPCState *env)
register_power6_common_sprs(env); register_power6_common_sprs(env);
register_HEIR64_spr(env); register_HEIR64_spr(env);
register_power6_dbg_sprs(env); register_power6_dbg_sprs(env);
register_power7_common_sprs(env);
register_power8_tce_address_control_sprs(env); register_power8_tce_address_control_sprs(env);
register_power8_ids_sprs(env); register_power8_ids_sprs(env);
register_power8_ebb_sprs(env); register_power8_ebb_sprs(env);
@ -6546,6 +6650,8 @@ static void init_proc_POWER10(CPUPPCState *env)
env->dcache_line_size = 128; env->dcache_line_size = 128;
env->icache_line_size = 128; env->icache_line_size = 128;
bhrb_init_state(env, POWER10_BHRB_ENTRIES_LOG2);
/* Allocate hardware IRQ controller */ /* Allocate hardware IRQ controller */
init_excp_POWER10(env); init_excp_POWER10(env);
ppcPOWER9_irq_init(env_archcpu(env)); ppcPOWER9_irq_init(env_archcpu(env));
@ -6588,6 +6694,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
PCR_COMPAT_2_06 | PCR_COMPAT_2_05; PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER10; pcc->init_proc = init_proc_POWER10;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->check_attn = check_attn_hid0_power9;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@ -6650,7 +6757,8 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
POWERPC_FLAG_VSX | POWERPC_FLAG_SCV; POWERPC_FLAG_VSX | POWERPC_FLAG_SCV |
POWERPC_FLAG_BHRB;
pcc->l1_dcache_size = 0x8000; pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000; pcc->l1_icache_size = 0x8000;
} }
@ -6661,6 +6769,7 @@ void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
CPUPPCState *env = &cpu->env; CPUPPCState *env = &cpu->env;
cpu->vhyp = vhyp; cpu->vhyp = vhyp;
cpu->vhyp_class = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(vhyp);
/* /*
* With a virtual hypervisor mode we never allow the CPU to go * With a virtual hypervisor mode we never allow the CPU to go
@ -6800,20 +6909,17 @@ static void init_ppc_proc(PowerPCCPU *cpu)
} }
/* Allocate TLBs buffer when needed */ /* Allocate TLBs buffer when needed */
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
if (env->nb_tlb != 0) { if (env->nb_tlb) {
int nb_tlb = env->nb_tlb;
if (env->id_tlbs != 0) {
nb_tlb *= 2;
}
switch (env->tlb_type) { switch (env->tlb_type) {
case TLB_6XX: case TLB_6XX:
env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, nb_tlb); /* 6xx has separate TLBs for instructions and data hence times 2 */
env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, 2 * env->nb_tlb);
break; break;
case TLB_EMB: case TLB_EMB:
env->tlb.tlbe = g_new0(ppcemb_tlb_t, nb_tlb); env->tlb.tlbe = g_new0(ppcemb_tlb_t, env->nb_tlb);
break; break;
case TLB_MAS: case TLB_MAS:
env->tlb.tlbm = g_new0(ppcmas_tlb_t, nb_tlb); env->tlb.tlbm = g_new0(ppcmas_tlb_t, env->nb_tlb);
break; break;
} }
/* Pre-compute some useful values */ /* Pre-compute some useful values */
@ -6824,6 +6930,11 @@ static void init_ppc_proc(PowerPCCPU *cpu)
warn_report("no power management check handler registered." warn_report("no power management check handler registered."
" Attempt QEMU to crash very soon !"); " Attempt QEMU to crash very soon !");
} }
if (env->check_attn == NULL) {
warn_report("no attn check handler registered."
" Attempt QEMU to crash very soon !");
}
} }
@ -7195,7 +7306,7 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
if (env->mmu_model != POWERPC_MMU_REAL) { if (env->mmu_model != POWERPC_MMU_REAL) {
ppc_tlb_invalidate_all(env); ppc_tlb_invalidate_all(env);
} }
pmu_mmcr01_updated(env); pmu_mmcr01a_updated(env);
} }
/* clean any pending stop state */ /* clean any pending stop state */
@ -7221,6 +7332,10 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
} }
env->spr[i] = spr->default_value; env->spr[i] = spr->default_value;
} }
#if defined(TARGET_PPC64)
bhrb_reset_state(env);
#endif
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
@ -7248,9 +7363,7 @@ static void ppc_cpu_exec_enter(CPUState *cs)
PowerPCCPU *cpu = POWERPC_CPU(cs); PowerPCCPU *cpu = POWERPC_CPU(cs);
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->cpu_exec_enter(cpu->vhyp, cpu);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->cpu_exec_enter(cpu->vhyp, cpu);
} }
} }
@ -7259,9 +7372,7 @@ static void ppc_cpu_exec_exit(CPUState *cs)
PowerPCCPU *cpu = POWERPC_CPU(cs); PowerPCCPU *cpu = POWERPC_CPU(cs);
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->cpu_exec_exit(cpu->vhyp, cpu);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->cpu_exec_exit(cpu->vhyp, cpu);
} }
} }
#endif /* CONFIG_TCG */ #endif /* CONFIG_TCG */
@ -7285,6 +7396,7 @@ static void ppc_cpu_instance_init(Object *obj)
env->flags = pcc->flags; env->flags = pcc->flags;
env->bfd_mach = pcc->bfd_mach; env->bfd_mach = pcc->bfd_mach;
env->check_pow = pcc->check_pow; env->check_pow = pcc->check_pow;
env->check_attn = pcc->check_attn;
/* /*
* Mark HV mode as supported if the CPU has an MSR_HV bit in the * Mark HV mode as supported if the CPU has an MSR_HV bit in the
@ -7409,6 +7521,11 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &ppc_sysemu_ops; cc->sysemu_ops = &ppc_sysemu_ops;
INTERRUPT_STATS_PROVIDER_CLASS(oc)->get_statistics = ppc_get_irq_stats; INTERRUPT_STATS_PROVIDER_CLASS(oc)->get_statistics = ppc_get_irq_stats;
/* check_prot_access_type relies on MMU access and PAGE bits relations */
qemu_build_assert(MMU_DATA_LOAD == 0 && MMU_DATA_STORE == 1 &&
MMU_INST_FETCH == 2 && PAGE_READ == 1 &&
PAGE_WRITE == 2 && PAGE_EXEC == 4);
#endif #endif
cc->gdb_num_core_regs = 71; cc->gdb_num_core_regs = 71;

View File

@ -19,6 +19,8 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "sysemu/sysemu.h"
#include "sysemu/runstate.h"
#include "cpu.h" #include "cpu.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "internal.h" #include "internal.h"
@ -152,6 +154,7 @@ static uint32_t ppc_ldl_code(CPUArchState *env, target_ulong addr)
return insn; return insn;
} }
#endif #endif
static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp) static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
@ -423,23 +426,57 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
env->reserve_addr = -1; env->reserve_addr = -1;
} }
static void powerpc_mcheck_checkstop(CPUPPCState *env) #ifdef CONFIG_TCG
/*
* This stops the machine and logs CPU state without killing QEMU (like
* cpu_abort()) because it is often a guest error as opposed to a QEMU error,
* so the machine can still be debugged.
*/
static G_NORETURN void powerpc_checkstop(CPUPPCState *env, const char *reason)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
FILE *f;
f = qemu_log_trylock();
if (f) {
fprintf(f, "Entering checkstop state: %s\n", reason);
cpu_dump_state(cs, f, CPU_DUMP_FPU | CPU_DUMP_CCOP);
qemu_log_unlock(f);
}
/*
* This stops the machine and logs CPU state without killing QEMU
* (like cpu_abort()) so the machine can still be debugged (because
* it is often a guest error).
*/
qemu_system_guest_panicked(NULL);
cpu_loop_exit_noexc(cs);
}
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
void helper_attn(CPUPPCState *env)
{
/* POWER attn is unprivileged when enabled by HID, otherwise illegal */
if ((*env->check_attn)(env)) {
powerpc_checkstop(env, "host executed attn");
} else {
raise_exception_err(env, POWERPC_EXCP_HV_EMU,
POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
}
}
#endif
#endif /* CONFIG_TCG */
static void powerpc_mcheck_checkstop(CPUPPCState *env)
{
/* KVM guests always have MSR[ME] enabled */
#ifdef CONFIG_TCG
if (FIELD_EX64(env->msr, MSR, ME)) { if (FIELD_EX64(env->msr, MSR, ME)) {
return; return;
} }
/* Machine check exception is not enabled. Enter checkstop state. */ powerpc_checkstop(env, "machine check with MSR[ME]=0");
fprintf(stderr, "Machine check while not allowed. " #endif
"Entering checkstop state\n");
if (qemu_log_separate()) {
qemu_log("Machine check while not allowed. "
"Entering checkstop state\n");
}
cs->halted = 1;
cpu_interrupt_exittb(cs);
} }
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
@ -794,9 +831,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
* HV mode, we need to keep hypercall support. * HV mode, we need to keep hypercall support.
*/ */
if (lev == 1 && cpu->vhyp) { if (lev == 1 && cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
powerpc_reset_excp_state(cpu); powerpc_reset_excp_state(cpu);
return; return;
} }
@ -946,9 +981,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
* HV mode, we need to keep hypercall support. * HV mode, we need to keep hypercall support.
*/ */
if (lev == 1 && cpu->vhyp) { if (lev == 1 && cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
powerpc_reset_excp_state(cpu); powerpc_reset_excp_state(cpu);
return; return;
} }
@ -1437,9 +1470,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
/* "PAPR mode" built-in hypercall emulation */ /* "PAPR mode" built-in hypercall emulation */
if (lev == 1 && books_vhyp_handles_hcall(cpu)) { if (lev == 1 && books_vhyp_handles_hcall(cpu)) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hypercall(cpu->vhyp, cpu);
powerpc_reset_excp_state(cpu); powerpc_reset_excp_state(cpu);
return; return;
} }
@ -1574,10 +1605,8 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
} }
if ((new_msr & MSR_HVB) && books_vhyp_handles_hv_excp(cpu)) { if ((new_msr & MSR_HVB) && books_vhyp_handles_hv_excp(cpu)) {
PPCVirtualHypervisorClass *vhc =
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
/* Deliver interrupt to L1 by returning from the H_ENTER_NESTED call */ /* Deliver interrupt to L1 by returning from the H_ENTER_NESTED call */
vhc->deliver_hv_excp(cpu, excp); cpu->vhyp_class->deliver_hv_excp(cpu, excp);
powerpc_reset_excp_state(cpu); powerpc_reset_excp_state(cpu);
} else { } else {
/* Sanity check */ /* Sanity check */
@ -2750,7 +2779,7 @@ void helper_rfmci(CPUPPCState *env)
} }
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, void helper_TW(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
uint32_t flags) uint32_t flags)
{ {
if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
@ -2764,7 +2793,7 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
} }
#ifdef TARGET_PPC64 #ifdef TARGET_PPC64
void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, void helper_TD(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
uint32_t flags) uint32_t flags)
{ {
if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
@ -2940,7 +2969,7 @@ void helper_msgsnd(target_ulong rb)
PowerPCCPU *cpu = POWERPC_CPU(cs); PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *cenv = &cpu->env; CPUPPCState *cenv = &cpu->env;
if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { if ((rb & DBELL_BRDCAST_MASK) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
ppc_set_irq(cpu, irq, 1); ppc_set_irq(cpu, irq, 1);
} }
} }
@ -2959,6 +2988,16 @@ static bool dbell_type_server(target_ulong rb)
return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER; return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER;
} }
static inline bool dbell_bcast_core(target_ulong rb)
{
return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_CORE;
}
static inline bool dbell_bcast_subproc(target_ulong rb)
{
return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC;
}
void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
{ {
if (!dbell_type_server(rb)) { if (!dbell_type_server(rb)) {
@ -2968,32 +3007,43 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0); ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
} }
static void book3s_msgsnd_common(int pir, int irq) void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
{
CPUState *cs;
bql_lock();
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *cenv = &cpu->env;
/* TODO: broadcast message to all threads of the same processor */
if (cenv->spr_cb[SPR_PIR].default_value == pir) {
ppc_set_irq(cpu, irq, 1);
}
}
bql_unlock();
}
void helper_book3s_msgsnd(target_ulong rb)
{ {
int pir = rb & DBELL_PROCIDTAG_MASK; int pir = rb & DBELL_PROCIDTAG_MASK;
bool brdcast = false;
CPUState *cs, *ccs;
PowerPCCPU *cpu;
if (!dbell_type_server(rb)) { if (!dbell_type_server(rb)) {
return; return;
} }
book3s_msgsnd_common(pir, PPC_INTERRUPT_HDOORBELL); cpu = ppc_get_vcpu_by_pir(pir);
if (!cpu) {
return;
}
cs = CPU(cpu);
if (dbell_bcast_core(rb) || (dbell_bcast_subproc(rb) &&
(env->flags & POWERPC_FLAG_SMT_1LPAR))) {
brdcast = true;
}
if (cs->nr_threads == 1 || !brdcast) {
ppc_set_irq(cpu, PPC_INTERRUPT_HDOORBELL, 1);
return;
}
/*
* Why is bql needed for walking CPU list? Answer seems to be because ppc
* irq handling needs it, but ppc_set_irq takes the lock itself if needed,
* so could this be removed?
*/
bql_lock();
THREAD_SIBLING_FOREACH(cs, ccs) {
ppc_set_irq(POWERPC_CPU(ccs), PPC_INTERRUPT_HDOORBELL, 1);
}
bql_unlock();
} }
#ifdef TARGET_PPC64 #ifdef TARGET_PPC64

View File

@ -490,54 +490,12 @@ static void float_invalid_op_addsub(CPUPPCState *env, int flags,
} }
} }
/* fadd - fadd. */ static inline void addsub_flags_handler(CPUPPCState *env, int flags,
float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) uintptr_t ra)
{ {
float64 ret = float64_add(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) { if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_addsub(env, flags, 1, GETPC()); float_invalid_op_addsub(env, flags, 1, ra);
} }
return ret;
}
/* fadds - fadds. */
float64 helper_fadds(CPUPPCState *env, float64 arg1, float64 arg2)
{
float64 ret = float64r32_add(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_addsub(env, flags, 1, GETPC());
}
return ret;
}
/* fsub - fsub. */
float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2)
{
float64 ret = float64_sub(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_addsub(env, flags, 1, GETPC());
}
return ret;
}
/* fsubs - fsubs. */
float64 helper_fsubs(CPUPPCState *env, float64 arg1, float64 arg2)
{
float64 ret = float64r32_sub(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_addsub(env, flags, 1, GETPC());
}
return ret;
} }
static void float_invalid_op_mul(CPUPPCState *env, int flags, static void float_invalid_op_mul(CPUPPCState *env, int flags,
@ -550,29 +508,11 @@ static void float_invalid_op_mul(CPUPPCState *env, int flags,
} }
} }
/* fmul - fmul. */ static inline void mul_flags_handler(CPUPPCState *env, int flags, uintptr_t ra)
float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2)
{ {
float64 ret = float64_mul(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) { if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_mul(env, flags, 1, GETPC()); float_invalid_op_mul(env, flags, 1, ra);
} }
return ret;
}
/* fmuls - fmuls. */
float64 helper_fmuls(CPUPPCState *env, float64 arg1, float64 arg2)
{
float64 ret = float64r32_mul(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_mul(env, flags, 1, GETPC());
}
return ret;
} }
static void float_invalid_op_div(CPUPPCState *env, int flags, static void float_invalid_op_div(CPUPPCState *env, int flags,
@ -587,36 +527,14 @@ static void float_invalid_op_div(CPUPPCState *env, int flags,
} }
} }
/* fdiv - fdiv. */ static inline void div_flags_handler(CPUPPCState *env, int flags, uintptr_t ra)
float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2)
{ {
float64 ret = float64_div(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) { if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_div(env, flags, 1, GETPC()); float_invalid_op_div(env, flags, 1, ra);
} }
if (unlikely(flags & float_flag_divbyzero)) { if (unlikely(flags & float_flag_divbyzero)) {
float_zero_divide_excp(env, GETPC()); float_zero_divide_excp(env, ra);
} }
return ret;
}
/* fdivs - fdivs. */
float64 helper_fdivs(CPUPPCState *env, float64 arg1, float64 arg2)
{
float64 ret = float64r32_div(arg1, arg2, &env->fp_status);
int flags = get_float_exception_flags(&env->fp_status);
if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_div(env, flags, 1, GETPC());
}
if (unlikely(flags & float_flag_divbyzero)) {
float_zero_divide_excp(env, GETPC());
}
return ret;
} }
static uint64_t float_invalid_cvt(CPUPPCState *env, int flags, static uint64_t float_invalid_cvt(CPUPPCState *env, int flags,
@ -755,7 +673,7 @@ static uint64_t do_fmadds(CPUPPCState *env, float64 a, float64 b,
uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \ uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \
uint64_t arg2, uint64_t arg3) \ uint64_t arg2, uint64_t arg3) \
{ return do_fmadd(env, arg1, arg2, arg3, madd_flags, GETPC()); } \ { return do_fmadd(env, arg1, arg2, arg3, madd_flags, GETPC()); } \
uint64_t helper_##op##s(CPUPPCState *env, uint64_t arg1, \ uint64_t helper_##op##S(CPUPPCState *env, uint64_t arg1, \
uint64_t arg2, uint64_t arg3) \ uint64_t arg2, uint64_t arg3) \
{ return do_fmadds(env, arg1, arg2, arg3, madd_flags, GETPC()); } { return do_fmadds(env, arg1, arg2, arg3, madd_flags, GETPC()); }
@ -764,10 +682,10 @@ static uint64_t do_fmadds(CPUPPCState *env, float64 a, float64 b,
#define NMADD_FLGS float_muladd_negate_result #define NMADD_FLGS float_muladd_negate_result
#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result) #define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
FPU_FMADD(fmadd, MADD_FLGS) FPU_FMADD(FMADD, MADD_FLGS)
FPU_FMADD(fnmadd, NMADD_FLGS) FPU_FMADD(FNMADD, NMADD_FLGS)
FPU_FMADD(fmsub, MSUB_FLGS) FPU_FMADD(FMSUB, MSUB_FLGS)
FPU_FMADD(fnmsub, NMSUB_FLGS) FPU_FMADD(FNMSUB, NMSUB_FLGS)
/* frsp - frsp. */ /* frsp - frsp. */
static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr) static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr)
@ -812,81 +730,66 @@ float64 helper_##name(CPUPPCState *env, float64 arg) \
FPU_FSQRT(FSQRT, float64_sqrt) FPU_FSQRT(FSQRT, float64_sqrt)
FPU_FSQRT(FSQRTS, float64r32_sqrt) FPU_FSQRT(FSQRTS, float64r32_sqrt)
/* fre - fre. */ #define FPU_FRE(name, op) \
float64 helper_fre(CPUPPCState *env, float64 arg) float64 helper_##name(CPUPPCState *env, float64 arg) \
{ { \
/* "Estimate" the reciprocal with actual division. */ /* "Estimate" the reciprocal with actual division. */ \
float64 ret = float64_div(float64_one, arg, &env->fp_status); float64 ret = op(float64_one, arg, &env->fp_status); \
int flags = get_float_exception_flags(&env->fp_status); int flags = get_float_exception_flags(&env->fp_status); \
\
if (unlikely(flags & float_flag_invalid_snan)) { if (unlikely(flags & float_flag_invalid_snan)) { \
float_invalid_op_vxsnan(env, GETPC()); float_invalid_op_vxsnan(env, GETPC()); \
} } \
if (unlikely(flags & float_flag_divbyzero)) { if (unlikely(flags & float_flag_divbyzero)) { \
float_zero_divide_excp(env, GETPC()); float_zero_divide_excp(env, GETPC()); \
/* For FPSCR.ZE == 0, the result is 1/2. */ /* For FPSCR.ZE == 0, the result is 1/2. */ \
ret = float64_set_sign(float64_half, float64_is_neg(arg)); ret = float64_set_sign(float64_half, float64_is_neg(arg)); \
} } \
\
return ret; return ret; \
} }
/* fres - fres. */ #define FPU_FRSQRTE(name, op) \
uint64_t helper_fres(CPUPPCState *env, uint64_t arg) float64 helper_##name(CPUPPCState *env, float64 arg) \
{ { \
/* "Estimate" the reciprocal with actual division. */ /* "Estimate" the reciprocal with actual division. */ \
float64 ret = float64r32_div(float64_one, arg, &env->fp_status); float64 rets = float64_sqrt(arg, &env->fp_status); \
int flags = get_float_exception_flags(&env->fp_status); float64 retd = op(float64_one, rets, &env->fp_status); \
int flags = get_float_exception_flags(&env->fp_status); \
if (unlikely(flags & float_flag_invalid_snan)) { \
float_invalid_op_vxsnan(env, GETPC()); if (unlikely(flags & float_flag_invalid)) { \
} float_invalid_op_sqrt(env, flags, 1, GETPC()); \
if (unlikely(flags & float_flag_divbyzero)) { } \
float_zero_divide_excp(env, GETPC()); if (unlikely(flags & float_flag_divbyzero)) { \
/* For FPSCR.ZE == 0, the result is 1/2. */ /* Reciprocal of (square root of) zero. */ \
ret = float64_set_sign(float64_half, float64_is_neg(arg)); float_zero_divide_excp(env, GETPC()); \
} } \
\
return ret; return retd; \
} }
/* frsqrte - frsqrte. */ #define FPU_HELPER(name, op, flags_handler) \
float64 helper_frsqrte(CPUPPCState *env, float64 arg) float64 helper_##name(CPUPPCState *env, float64 arg1, float64 arg2) \
{ { \
/* "Estimate" the reciprocal with actual division. */ float64 ret = op(arg1, arg2, &env->fp_status); \
float64 rets = float64_sqrt(arg, &env->fp_status); int flags = get_float_exception_flags(&env->fp_status); \
float64 retd = float64_div(float64_one, rets, &env->fp_status); uintptr_t ra = GETPC(); \
int flags = get_float_exception_flags(&env->fp_status); flags_handler(env, flags, ra); \
return ret; \
if (unlikely(flags & float_flag_invalid)) {
float_invalid_op_sqrt(env, flags, 1, GETPC());
}
if (unlikely(flags & float_flag_divbyzero)) {
/* Reciprocal of (square root of) zero. */
float_zero_divide_excp(env, GETPC());
}
return retd;
} }
/* frsqrtes - frsqrtes. */ FPU_FRE(FRE, float64_div)
float64 helper_frsqrtes(CPUPPCState *env, float64 arg) FPU_FRE(FRES, float64r32_div)
{ FPU_FRSQRTE(FRSQRTE, float64_div)
/* "Estimate" the reciprocal with actual division. */ FPU_FRSQRTE(FRSQRTES, float64r32_div)
float64 rets = float64_sqrt(arg, &env->fp_status); FPU_HELPER(FADD, float64_add, addsub_flags_handler)
float64 retd = float64r32_div(float64_one, rets, &env->fp_status); FPU_HELPER(FADDS, float64r32_add, addsub_flags_handler)
int flags = get_float_exception_flags(&env->fp_status); FPU_HELPER(FSUB, float64_sub, addsub_flags_handler)
FPU_HELPER(FSUBS, float64r32_sub, addsub_flags_handler)
if (unlikely(flags & float_flag_invalid)) { FPU_HELPER(FMUL, float64_mul, mul_flags_handler)
float_invalid_op_sqrt(env, flags, 1, GETPC()); FPU_HELPER(FMULS, float64r32_mul, mul_flags_handler)
} FPU_HELPER(FDIV, float64_div, div_flags_handler)
if (unlikely(flags & float_flag_divbyzero)) { FPU_HELPER(FDIVS, float64r32_div, div_flags_handler)
/* Reciprocal of (square root of) zero. */
float_zero_divide_excp(env, GETPC());
}
return retd;
}
/* fsel - fsel. */ /* fsel - fsel. */
uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c) uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c)
@ -903,7 +806,7 @@ uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c)
} }
} }
uint32_t helper_ftdiv(uint64_t fra, uint64_t frb) uint32_t helper_FTDIV(uint64_t fra, uint64_t frb)
{ {
int fe_flag = 0; int fe_flag = 0;
int fg_flag = 0; int fg_flag = 0;
@ -939,7 +842,7 @@ uint32_t helper_ftdiv(uint64_t fra, uint64_t frb)
return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
} }
uint32_t helper_ftsqrt(uint64_t frb) uint32_t helper_FTSQRT(uint64_t frb)
{ {
int fe_flag = 0; int fe_flag = 0;
int fg_flag = 0; int fg_flag = 0;

View File

@ -1,8 +1,8 @@
DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, noreturn, env, i32, i32) DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, noreturn, env, i32, i32)
DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32) DEF_HELPER_FLAGS_4(TW, TCG_CALL_NO_WG, void, env, tl, tl, i32)
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32) DEF_HELPER_FLAGS_4(TD, TCG_CALL_NO_WG, void, env, tl, tl, i32)
#endif #endif
DEF_HELPER_4(HASHST, void, env, tl, tl, tl) DEF_HELPER_4(HASHST, void, env, tl, tl, tl)
DEF_HELPER_4(HASHCHK, void, env, tl, tl, tl) DEF_HELPER_4(HASHCHK, void, env, tl, tl, tl)
@ -30,6 +30,7 @@ DEF_HELPER_2(store_dawr0, void, env, tl)
DEF_HELPER_2(store_dawrx0, void, env, tl) DEF_HELPER_2(store_dawrx0, void, env, tl)
DEF_HELPER_2(store_mmcr0, void, env, tl) DEF_HELPER_2(store_mmcr0, void, env, tl)
DEF_HELPER_2(store_mmcr1, void, env, tl) DEF_HELPER_2(store_mmcr1, void, env, tl)
DEF_HELPER_2(store_mmcrA, void, env, tl)
DEF_HELPER_3(store_pmc, void, env, i32, i64) DEF_HELPER_3(store_pmc, void, env, i32, i64)
DEF_HELPER_2(read_pmc, tl, env, i32) DEF_HELPER_2(read_pmc, tl, env, i32)
DEF_HELPER_2(insns_inc, void, env, i32) DEF_HELPER_2(insns_inc, void, env, i32)
@ -52,14 +53,14 @@ DEF_HELPER_FLAGS_2(icbiep, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
DEF_HELPER_4(divdeu, i64, env, i64, i64, i32) DEF_HELPER_4(DIVDEU, i64, env, i64, i64, i32)
DEF_HELPER_4(divde, i64, env, i64, i64, i32) DEF_HELPER_4(DIVDE, i64, env, i64, i64, i32)
#endif #endif
DEF_HELPER_4(divweu, tl, env, tl, tl, i32) DEF_HELPER_4(DIVWEU, tl, env, tl, tl, i32)
DEF_HELPER_4(divwe, tl, env, tl, tl, i32) DEF_HELPER_4(DIVWE, tl, env, tl, tl, i32)
DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(POPCNTB, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_FLAGS_2(CMPB, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_3(sraw, tl, env, tl, tl) DEF_HELPER_3(sraw, tl, env, tl, tl)
DEF_HELPER_FLAGS_2(CFUGED, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(CFUGED, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(PDEPD, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(PDEPD, TCG_CALL_NO_RWG_SE, i64, i64, i64)
@ -67,12 +68,12 @@ DEF_HELPER_FLAGS_2(PEXTD, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_1(CDTBCD, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(CDTBCD, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(CBCDTD, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(CBCDTD, TCG_CALL_NO_RWG_SE, tl, tl)
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_2(cmpeqb, TCG_CALL_NO_RWG_SE, i32, tl, tl) DEF_HELPER_FLAGS_2(CMPEQB, TCG_CALL_NO_RWG_SE, i32, tl, tl)
DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(POPCNTW, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(BPERMD, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_3(srad, tl, env, tl, tl) DEF_HELPER_3(srad, tl, env, tl, tl)
DEF_HELPER_FLAGS_0(darn32, TCG_CALL_NO_RWG, tl) DEF_HELPER_FLAGS_0(DARN32, TCG_CALL_NO_RWG, tl)
DEF_HELPER_FLAGS_0(darn64, TCG_CALL_NO_RWG, tl) DEF_HELPER_FLAGS_0(DARN64, TCG_CALL_NO_RWG, tl)
#endif #endif
DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32)
@ -110,32 +111,32 @@ DEF_HELPER_2(friz, i64, env, i64)
DEF_HELPER_2(frip, i64, env, i64) DEF_HELPER_2(frip, i64, env, i64)
DEF_HELPER_2(frim, i64, env, i64) DEF_HELPER_2(frim, i64, env, i64)
DEF_HELPER_3(fadd, f64, env, f64, f64) DEF_HELPER_3(FADD, f64, env, f64, f64)
DEF_HELPER_3(fadds, f64, env, f64, f64) DEF_HELPER_3(FADDS, f64, env, f64, f64)
DEF_HELPER_3(fsub, f64, env, f64, f64) DEF_HELPER_3(FSUB, f64, env, f64, f64)
DEF_HELPER_3(fsubs, f64, env, f64, f64) DEF_HELPER_3(FSUBS, f64, env, f64, f64)
DEF_HELPER_3(fmul, f64, env, f64, f64) DEF_HELPER_3(FMUL, f64, env, f64, f64)
DEF_HELPER_3(fmuls, f64, env, f64, f64) DEF_HELPER_3(FMULS, f64, env, f64, f64)
DEF_HELPER_3(fdiv, f64, env, f64, f64) DEF_HELPER_3(FDIV, f64, env, f64, f64)
DEF_HELPER_3(fdivs, f64, env, f64, f64) DEF_HELPER_3(FDIVS, f64, env, f64, f64)
DEF_HELPER_4(fmadd, i64, env, i64, i64, i64) DEF_HELPER_4(FMADD, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsub, i64, env, i64, i64, i64) DEF_HELPER_4(FMSUB, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64) DEF_HELPER_4(FNMADD, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64) DEF_HELPER_4(FNMSUB, i64, env, i64, i64, i64)
DEF_HELPER_4(fmadds, i64, env, i64, i64, i64) DEF_HELPER_4(FMADDS, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsubs, i64, env, i64, i64, i64) DEF_HELPER_4(FMSUBS, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmadds, i64, env, i64, i64, i64) DEF_HELPER_4(FNMADDS, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmsubs, i64, env, i64, i64, i64) DEF_HELPER_4(FNMSUBS, i64, env, i64, i64, i64)
DEF_HELPER_2(FSQRT, f64, env, f64) DEF_HELPER_2(FSQRT, f64, env, f64)
DEF_HELPER_2(FSQRTS, f64, env, f64) DEF_HELPER_2(FSQRTS, f64, env, f64)
DEF_HELPER_2(fre, i64, env, i64) DEF_HELPER_2(FRE, i64, env, i64)
DEF_HELPER_2(fres, i64, env, i64) DEF_HELPER_2(FRES, i64, env, i64)
DEF_HELPER_2(frsqrte, i64, env, i64) DEF_HELPER_2(FRSQRTE, i64, env, i64)
DEF_HELPER_2(frsqrtes, i64, env, i64) DEF_HELPER_2(FRSQRTES, i64, env, i64)
DEF_HELPER_FLAGS_3(FSEL, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) DEF_HELPER_FLAGS_3(FSEL, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
DEF_HELPER_FLAGS_2(ftdiv, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(FTDIV, TCG_CALL_NO_RWG_SE, i32, i64, i64)
DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) DEF_HELPER_FLAGS_1(FTSQRT, TCG_CALL_NO_RWG_SE, i32, i64)
#define dh_alias_avr ptr #define dh_alias_avr ptr
#define dh_ctype_avr ppc_avr_t * #define dh_ctype_avr ppc_avr_t *
@ -267,12 +268,12 @@ DEF_HELPER_5(VMSUMSHS, void, env, avr, avr, avr, avr)
DEF_HELPER_FLAGS_5(VMLADDUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(VMLADDUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env) DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env)
DEF_HELPER_3(lvebx, void, env, avr, tl) DEF_HELPER_3(LVEBX, void, env, avr, tl)
DEF_HELPER_3(lvehx, void, env, avr, tl) DEF_HELPER_3(LVEHX, void, env, avr, tl)
DEF_HELPER_3(lvewx, void, env, avr, tl) DEF_HELPER_3(LVEWX, void, env, avr, tl)
DEF_HELPER_3(stvebx, void, env, avr, tl) DEF_HELPER_3(STVEBX, void, env, avr, tl)
DEF_HELPER_3(stvehx, void, env, avr, tl) DEF_HELPER_3(STVEHX, void, env, avr, tl)
DEF_HELPER_3(stvewx, void, env, avr, tl) DEF_HELPER_3(STVEWX, void, env, avr, tl)
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
DEF_HELPER_4(lxvl, void, env, tl, vsr, tl) DEF_HELPER_4(lxvl, void, env, tl, vsr, tl)
DEF_HELPER_4(lxvll, void, env, tl, vsr, tl) DEF_HELPER_4(lxvll, void, env, tl, vsr, tl)
@ -694,14 +695,12 @@ DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_1(msgsnd, void, tl)
DEF_HELPER_2(msgclr, void, env, tl) DEF_HELPER_2(msgclr, void, env, tl)
DEF_HELPER_1(book3s_msgsnd, void, tl) DEF_HELPER_2(book3s_msgsnd, void, env, tl)
DEF_HELPER_2(book3s_msgclr, void, env, tl) DEF_HELPER_2(book3s_msgclr, void, env, tl)
#endif #endif
DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
DEF_HELPER_2(rac, tl, env, tl)
DEF_HELPER_2(load_dcr, tl, env, tl) DEF_HELPER_2(load_dcr, tl, env, tl)
DEF_HELPER_3(store_dcr, void, env, tl, tl) DEF_HELPER_3(store_dcr, void, env, tl, tl)
#endif #endif
@ -729,6 +728,9 @@ DEF_HELPER_2(book3s_msgsndp, void, env, tl)
DEF_HELPER_2(book3s_msgclrp, void, env, tl) DEF_HELPER_2(book3s_msgclrp, void, env, tl)
DEF_HELPER_1(load_tfmr, tl, env) DEF_HELPER_1(load_tfmr, tl, env)
DEF_HELPER_2(store_tfmr, void, env, tl) DEF_HELPER_2(store_tfmr, void, env, tl)
DEF_HELPER_FLAGS_2(store_sprc, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(load_sprd, TCG_CALL_NO_RWG_SE, tl, env)
DEF_HELPER_FLAGS_2(store_sprd, TCG_CALL_NO_RWG, void, env, tl)
#endif #endif
DEF_HELPER_2(store_sdr1, void, env, tl) DEF_HELPER_2(store_sdr1, void, env, tl)
DEF_HELPER_2(store_pidr, void, env, tl) DEF_HELPER_2(store_pidr, void, env, tl)
@ -819,3 +821,11 @@ DEF_HELPER_4(DSCLIQ, void, env, fprp, fprp, i32)
DEF_HELPER_1(tbegin, void, env) DEF_HELPER_1(tbegin, void, env)
DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG, void, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
DEF_HELPER_1(clrbhrb, void, env)
DEF_HELPER_FLAGS_2(mfbhrbe, TCG_CALL_NO_WG, i64, env, i32)
DEF_HELPER_1(attn, noreturn, env)
#endif
#endif

View File

@ -47,6 +47,39 @@ void hreg_swap_gpr_tgpr(CPUPPCState *env)
env->tgpr[3] = tmp; env->tgpr[3] = tmp;
} }
#if defined(TARGET_PPC64)
static bool hreg_check_bhrb_enable(CPUPPCState *env)
{
bool pr = !!(env->msr & (1 << MSR_PR));
target_long mmcr0;
bool fcp;
bool hv;
/* ISA 3.1 adds the PMCRA[BRHBRD] and problem state checks */
if ((env->insns_flags2 & PPC2_ISA310) &&
((env->spr[SPR_POWER_MMCRA] & MMCRA_BHRBRD) || !pr)) {
return false;
}
/* Check for BHRB "frozen" conditions */
mmcr0 = env->spr[SPR_POWER_MMCR0];
fcp = !!(mmcr0 & MMCR0_FCP);
if (mmcr0 & MMCR0_FCPC) {
hv = !!(env->msr & (1ull << MSR_HV));
if (fcp) {
if (hv && pr) {
return false;
}
} else if (!hv && pr) {
return false;
}
} else if (fcp && pr) {
return false;
}
return true;
}
#endif
static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env) static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env)
{ {
uint32_t hflags = 0; uint32_t hflags = 0;
@ -61,6 +94,9 @@ static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env)
if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) { if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) {
hflags |= 1 << HFLAGS_PMCJCE; hflags |= 1 << HFLAGS_PMCJCE;
} }
if (hreg_check_bhrb_enable(env)) {
hflags |= 1 << HFLAGS_BHRB_ENABLE;
}
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (env->pmc_ins_cnt) { if (env->pmc_ins_cnt) {
@ -85,6 +121,7 @@ static uint32_t hreg_compute_pmu_hflags_mask(CPUPPCState *env)
hflags_mask |= 1 << HFLAGS_PMCJCE; hflags_mask |= 1 << HFLAGS_PMCJCE;
hflags_mask |= 1 << HFLAGS_INSN_CNT; hflags_mask |= 1 << HFLAGS_INSN_CNT;
hflags_mask |= 1 << HFLAGS_PMC_OTHER; hflags_mask |= 1 << HFLAGS_PMC_OTHER;
hflags_mask |= 1 << HFLAGS_BHRB_ENABLE;
#endif #endif
return hflags_mask; return hflags_mask;
} }
@ -334,7 +371,7 @@ void check_tlb_flush(CPUPPCState *env, bool global)
if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) {
env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH;
env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH;
tlb_flush_all_cpus(cs); tlb_flush_all_cpus_synced(cs);
return; return;
} }
@ -693,7 +730,6 @@ void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
env->nb_tlb = nb_tlbs; env->nb_tlb = nb_tlbs;
env->nb_ways = nb_ways; env->nb_ways = nb_ways;
env->id_tlbs = 1;
env->tlb_type = TLB_6XX; env->tlb_type = TLB_6XX;
spr_register(env, SPR_DMISS, "DMISS", spr_register(env, SPR_DMISS, "DMISS",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,

View File

@ -20,12 +20,24 @@
&A frt fra frb frc rc:bool &A frt fra frb frc rc:bool
@A ...... frt:5 fra:5 frb:5 frc:5 ..... rc:1 &A @A ...... frt:5 fra:5 frb:5 frc:5 ..... rc:1 &A
&A_tab frt fra frb rc:bool
@A_tab ...... frt:5 fra:5 frb:5 ..... ..... rc:1 &A_tab
&A_tac frt fra frc rc:bool
@A_tac ...... frt:5 fra:5 ..... frc:5 ..... rc:1 &A_tac
&A_tb frt frb rc:bool &A_tb frt frb rc:bool
@A_tb ...... frt:5 ..... frb:5 ..... ..... rc:1 &A_tb @A_tb ...... frt:5 ..... frb:5 ..... ..... rc:1 &A_tb
&A_tab_bc rt ra rb bc
@A_tab_bc ...... rt:5 ra:5 rb:5 bc:5 ..... . &A_tab_bc
&D rt ra si:int64_t &D rt ra si:int64_t
@D ...... rt:5 ra:5 si:s16 &D @D ...... rt:5 ra:5 si:s16 &D
&D_ui rt ra ui:uint64_t
@D_ui ...... rt:5 ra:5 ui:16 &D_ui
&D_bf bf l:bool ra imm &D_bf bf l:bool ra imm
@D_bfs ...... bf:3 . l:1 ra:5 imm:s16 &D_bf @D_bfs ...... bf:3 . l:1 ra:5 imm:s16 &D_bf
@D_bfu ...... bf:3 . l:1 ra:5 imm:16 &D_bf @D_bfu ...... bf:3 . l:1 ra:5 imm:16 &D_bf
@ -93,6 +105,9 @@
&X_sa rs ra &X_sa rs ra
@X_sa ...... rs:5 ra:5 ..... .......... . &X_sa @X_sa ...... rs:5 ra:5 ..... .......... . &X_sa
&X_sa_rc rs ra rc
@X_sa_rc ...... rs:5 ra:5 ..... .......... rc:1 &X_sa_rc
%x_frtp 22:4 !function=times_2 %x_frtp 22:4 !function=times_2
%x_frap 17:4 !function=times_2 %x_frap 17:4 !function=times_2
%x_frbp 12:4 !function=times_2 %x_frbp 12:4 !function=times_2
@ -124,6 +139,9 @@
&X_bf bf ra rb &X_bf bf ra rb
@X_bf ...... bf:3 .. ra:5 rb:5 .......... . &X_bf @X_bf ...... bf:3 .. ra:5 rb:5 .......... . &X_bf
&X_bf_b bf rb
@X_bf_b ...... bf:3 .. ..... rb:5 .......... . &X_bf_b
@X_bf_ap_bp ...... bf:3 .. ....0 ....0 .......... . &X_bf ra=%x_frap rb=%x_frbp @X_bf_ap_bp ...... bf:3 .. ....0 ....0 .......... . &X_bf ra=%x_frap rb=%x_frbp
@X_bf_a_bp ...... bf:3 .. ra:5 ....0 .......... . &X_bf rb=%x_frbp @X_bf_a_bp ...... bf:3 .. ra:5 ....0 .......... . &X_bf rb=%x_frbp
@ -187,12 +205,18 @@
&X_a ra &X_a ra
@X_a ...... ra:3 .. ..... ..... .......... . &X_a @X_a ...... ra:3 .. ..... ..... .......... . &X_a
&X_tl rt l
@X_tl ...... rt:5 ... l:2 ..... .......... . &X_tl
&XO rt ra rb oe:bool rc:bool &XO rt ra rb oe:bool rc:bool
@XO ...... rt:5 ra:5 rb:5 oe:1 ......... rc:1 &XO @XO ...... rt:5 ra:5 rb:5 oe:1 ......... rc:1 &XO
&XO_ta rt ra oe:bool rc:bool &XO_ta rt ra oe:bool rc:bool
@XO_ta ...... rt:5 ra:5 ..... oe:1 ......... rc:1 &XO_ta @XO_ta ...... rt:5 ra:5 ..... oe:1 ......... rc:1 &XO_ta
&XO_tab_rc rt ra rb rc:bool
@XO_tab_rc ...... rt:5 ra:5 rb:5 . ......... rc:1 &XO_tab_rc
%xx_xt 0:1 21:5 %xx_xt 0:1 21:5
%xx_xb 1:1 11:5 %xx_xb 1:1 11:5
%xx_xa 2:1 16:5 %xx_xa 2:1 16:5
@ -325,6 +349,19 @@ CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl
CMPL 011111 ... - . ..... ..... 0000100000 - @X_bfl CMPL 011111 ... - . ..... ..... 0000100000 - @X_bfl
CMPI 001011 ... - . ..... ................ @D_bfs CMPI 001011 ... - . ..... ................ @D_bfs
CMPLI 001010 ... - . ..... ................ @D_bfu CMPLI 001010 ... - . ..... ................ @D_bfu
CMPRB 011111 ... - . ..... ..... 0011000000 - @X_bfl
CMPEQB 011111 ... -- ..... ..... 0011100000 - @X_bf
### Fixed-Point Trap Instructions
TW 011111 ..... ..... ..... 0000000100 - @X
TD 011111 ..... ..... ..... 0001000100 - @X
TWI 000011 ..... ..... ................ @D
TDI 000010 ..... ..... ................ @D
### Fixed-Point Select Instruction
ISEL 011111 ..... ..... ..... ..... 01111 - @A_tab_bc
### Fixed-Point Arithmetic Instructions ### Fixed-Point Arithmetic Instructions
@ -353,8 +390,73 @@ SUBFE 011111 ..... ..... ..... . 010001000 . @XO
SUBFME 011111 ..... ..... ----- . 011101000 . @XO_ta SUBFME 011111 ..... ..... ----- . 011101000 . @XO_ta
SUBFZE 011111 ..... ..... ----- . 011001000 . @XO_ta SUBFZE 011111 ..... ..... ----- . 011001000 . @XO_ta
MULLI 000111 ..... ..... ................ @D
MULLW 011111 ..... ..... ..... 0 011101011 . @XO_tab_rc
MULLWO 011111 ..... ..... ..... 1 011101011 . @XO_tab_rc
MULHW 011111 ..... ..... ..... - 001001011 . @XO_tab_rc
MULHWU 011111 ..... ..... ..... - 000001011 . @XO_tab_rc
DIVW 011111 ..... ..... ..... . 111101011 . @XO
DIVWU 011111 ..... ..... ..... . 111001011 . @XO
DIVWE 011111 ..... ..... ..... . 110101011 . @XO
DIVWEU 011111 ..... ..... ..... . 110001011 . @XO
MODSW 011111 ..... ..... ..... 1100001011 - @X
MODUW 011111 ..... ..... ..... 0100001011 - @X
DARN 011111 ..... --- .. ----- 1011110011 - @X_tl
NEG 011111 ..... ..... ----- . 001101000 . @XO_ta
MULLD 011111 ..... ..... ..... 0 011101001 . @XO_tab_rc
MULLDO 011111 ..... ..... ..... 1 011101001 . @XO_tab_rc
MULHD 011111 ..... ..... ..... - 001001001 . @XO_tab_rc
MULHDU 011111 ..... ..... ..... - 000001001 . @XO_tab_rc
MADDLD 000100 ..... ..... ..... ..... 110011 @VA
MADDHD 000100 ..... ..... ..... ..... 110000 @VA
MADDHDU 000100 ..... ..... ..... ..... 110001 @VA
DIVD 011111 ..... ..... ..... . 111101001 . @XO
DIVDU 011111 ..... ..... ..... . 111001001 . @XO
DIVDE 011111 ..... ..... ..... . 110101001 . @XO
DIVDEU 011111 ..... ..... ..... . 110001001 . @XO
MODSD 011111 ..... ..... ..... 1100001001 - @X
MODUD 011111 ..... ..... ..... 0100001001 - @X
## Fixed-Point Logical Instructions ## Fixed-Point Logical Instructions
ANDI_ 011100 ..... ..... ................ @D_ui
ANDIS_ 011101 ..... ..... ................ @D_ui
ORI 011000 ..... ..... ................ @D_ui
ORIS 011001 ..... ..... ................ @D_ui
XORI 011010 ..... ..... ................ @D_ui
XORIS 011011 ..... ..... ................ @D_ui
AND 011111 ..... ..... ..... 0000011100 . @X_rc
ANDC 011111 ..... ..... ..... 0000111100 . @X_rc
NAND 011111 ..... ..... ..... 0111011100 . @X_rc
OR 011111 ..... ..... ..... 0110111100 . @X_rc
ORC 011111 ..... ..... ..... 0110011100 . @X_rc
NOR 011111 ..... ..... ..... 0001111100 . @X_rc
XOR 011111 ..... ..... ..... 0100111100 . @X_rc
EQV 011111 ..... ..... ..... 0100011100 . @X_rc
CMPB 011111 ..... ..... ..... 0111111100 . @X_rc
EXTSB 011111 ..... ..... ----- 1110111010 . @X_sa_rc
EXTSH 011111 ..... ..... ----- 1110011010 . @X_sa_rc
EXTSW 011111 ..... ..... ----- 1111011010 . @X_sa_rc
CNTLZW 011111 ..... ..... ----- 0000011010 . @X_sa_rc
CNTTZW 011111 ..... ..... ----- 1000011010 . @X_sa_rc
CNTLZD 011111 ..... ..... ----- 0000111010 . @X_sa_rc
CNTTZD 011111 ..... ..... ----- 1000111010 . @X_sa_rc
POPCNTB 011111 ..... ..... ----- 0001111010 . @X_sa_rc
POPCNTW 011111 ..... ..... ----- 0101111010 - @X_sa
POPCNTD 011111 ..... ..... ----- 0111111010 - @X_sa
PRTYW 011111 ..... ..... ----- 0010011010 - @X_sa
PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa
BPERMD 011111 ..... ..... ..... 0011111100 - @X
CFUGED 011111 ..... ..... ..... 0011011100 - @X CFUGED 011111 ..... ..... ..... 0011011100 - @X
CNTLZDM 011111 ..... ..... ..... 0000111011 - @X CNTLZDM 011111 ..... ..... ..... 0000111011 - @X
CNTTZDM 011111 ..... ..... ..... 1000111011 - @X CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
@ -400,9 +502,42 @@ STFDUX 011111 ..... ...... .... 1011110111 - @X
### Floating-Point Arithmetic Instructions ### Floating-Point Arithmetic Instructions
FADD 111111 ..... ..... ..... ----- 10101 . @A_tab
FADDS 111011 ..... ..... ..... ----- 10101 . @A_tab
FSUB 111111 ..... ..... ..... ----- 10100 . @A_tab
FSUBS 111011 ..... ..... ..... ----- 10100 . @A_tab
FMUL 111111 ..... ..... ----- ..... 11001 . @A_tac
FMULS 111011 ..... ..... ----- ..... 11001 . @A_tac
FDIV 111111 ..... ..... ..... ----- 10010 . @A_tab
FDIVS 111011 ..... ..... ..... ----- 10010 . @A_tab
FSQRT 111111 ..... ----- ..... ----- 10110 . @A_tb FSQRT 111111 ..... ----- ..... ----- 10110 . @A_tb
FSQRTS 111011 ..... ----- ..... ----- 10110 . @A_tb FSQRTS 111011 ..... ----- ..... ----- 10110 . @A_tb
FRE 111111 ..... ----- ..... ----- 11000 . @A_tb
FRES 111011 ..... ----- ..... ----- 11000 . @A_tb
FRSQRTE 111111 ..... ----- ..... ----- 11010 . @A_tb
FRSQRTES 111011 ..... ----- ..... ----- 11010 . @A_tb
FTDIV 111111 ... -- ..... ..... 0010000000 - @X_bf
FTSQRT 111111 ... -- ----- ..... 0010100000 - @X_bf_b
FMADD 111111 ..... ..... ..... ..... 11101 . @A
FMADDS 111011 ..... ..... ..... ..... 11101 . @A
FMSUB 111111 ..... ..... ..... ..... 11100 . @A
FMSUBS 111011 ..... ..... ..... ..... 11100 . @A
FNMADD 111111 ..... ..... ..... ..... 11111 . @A
FNMADDS 111011 ..... ..... ..... ..... 11111 . @A
FNMSUB 111111 ..... ..... ..... ..... 11110 . @A
FNMSUBS 111011 ..... ..... ..... ..... 11110 . @A
### Floating-Point Select Instruction ### Floating-Point Select Instruction
FSEL 111111 ..... ..... ..... ..... 10111 . @A FSEL 111111 ..... ..... ..... ..... 10111 . @A
@ -526,6 +661,23 @@ DSCRIQ 111111 ..... ..... ...... 001100010 . @Z22_tap_sh_rc
VPMSUMD 000100 ..... ..... ..... 10011001000 @VX VPMSUMD 000100 ..... ..... ..... 10011001000 @VX
## Vector Load/Store Instructions
LVEBX 011111 ..... ..... ..... 0000000111 - @X
LVEHX 011111 ..... ..... ..... 0000100111 - @X
LVEWX 011111 ..... ..... ..... 0001000111 - @X
LVX 011111 ..... ..... ..... 0001100111 - @X
LVXL 011111 ..... ..... ..... 0101100111 - @X
STVEBX 011111 ..... ..... ..... 0010000111 - @X
STVEHX 011111 ..... ..... ..... 0010100111 - @X
STVEWX 011111 ..... ..... ..... 0011000111 - @X
STVX 011111 ..... ..... ..... 0011100111 - @X
STVXL 011111 ..... ..... ..... 0111100111 - @X
LVSL 011111 ..... ..... ..... 0000000110 - @X
LVSR 011111 ..... ..... ..... 0000100110 - @X
## Vector Integer Instructions ## Vector Integer Instructions
VCMPEQUB 000100 ..... ..... ..... . 0000000110 @VC VCMPEQUB 000100 ..... ..... ..... . 0000000110 @VC
@ -557,6 +709,17 @@ VCMPNEZW 000100 ..... ..... ..... . 0110000111 @VC
VCMPSQ 000100 ... -- ..... ..... 00101000001 @VX_bf VCMPSQ 000100 ... -- ..... ..... 00101000001 @VX_bf
VCMPUQ 000100 ... -- ..... ..... 00100000001 @VX_bf VCMPUQ 000100 ... -- ..... ..... 00100000001 @VX_bf
## Vector Integer Logical Instructions
VAND 000100 ..... ..... ..... 10000000100 @VX
VANDC 000100 ..... ..... ..... 10001000100 @VX
VNAND 000100 ..... ..... ..... 10110000100 @VX
VOR 000100 ..... ..... ..... 10010000100 @VX
VORC 000100 ..... ..... ..... 10101000100 @VX
VNOR 000100 ..... ..... ..... 10100000100 @VX
VXOR 000100 ..... ..... ..... 10011000100 @VX
VEQV 000100 ..... ..... ..... 11010000100 @VX
## Vector Integer Average Instructions ## Vector Integer Average Instructions
VAVGSB 000100 ..... ..... ..... 10100000010 @VX VAVGSB 000100 ..... ..... ..... 10100000010 @VX
@ -689,6 +852,28 @@ VEXTSD2Q 000100 ..... 11011 ..... 11000000010 @VX_tb
VNEGD 000100 ..... 00111 ..... 11000000010 @VX_tb VNEGD 000100 ..... 00111 ..... 11000000010 @VX_tb
VNEGW 000100 ..... 00110 ..... 11000000010 @VX_tb VNEGW 000100 ..... 00110 ..... 11000000010 @VX_tb
## Vector Integer Maximum/Minimum Instructions
VMAXUB 000100 ..... ..... ..... 00000000010 @VX
VMAXUH 000100 ..... ..... ..... 00001000010 @VX
VMAXUW 000100 ..... ..... ..... 00010000010 @VX
VMAXUD 000100 ..... ..... ..... 00011000010 @VX
VMAXSB 000100 ..... ..... ..... 00100000010 @VX
VMAXSH 000100 ..... ..... ..... 00101000010 @VX
VMAXSW 000100 ..... ..... ..... 00110000010 @VX
VMAXSD 000100 ..... ..... ..... 00111000010 @VX
VMINUB 000100 ..... ..... ..... 01000000010 @VX
VMINUH 000100 ..... ..... ..... 01001000010 @VX
VMINUW 000100 ..... ..... ..... 01010000010 @VX
VMINUD 000100 ..... ..... ..... 01011000010 @VX
VMINSB 000100 ..... ..... ..... 01100000010 @VX
VMINSH 000100 ..... ..... ..... 01101000010 @VX
VMINSW 000100 ..... ..... ..... 01110000010 @VX
VMINSD 000100 ..... ..... ..... 01111000010 @VX
## Vector Mask Manipulation Instructions ## Vector Mask Manipulation Instructions
MTVSRBM 000100 ..... 10000 ..... 11001000010 @VX_tb MTVSRBM 000100 ..... 10000 ..... 11001000010 @VX_tb
@ -998,3 +1183,22 @@ MSGSND 011111 ----- ----- ..... 0011001110 - @X_rb
MSGCLRP 011111 ----- ----- ..... 0010101110 - @X_rb MSGCLRP 011111 ----- ----- ..... 0010101110 - @X_rb
MSGSNDP 011111 ----- ----- ..... 0010001110 - @X_rb MSGSNDP 011111 ----- ----- ..... 0010001110 - @X_rb
MSGSYNC 011111 ----- ----- ----- 1101110110 - MSGSYNC 011111 ----- ----- ----- 1101110110 -
# Memory Barrier Instructions
&X_sync l sc
@X_sync ...... .. l:3 ... sc:2 ..... .......... . &X_sync
SYNC 011111 -- ... --- .. ----- 1001010110 - @X_sync
EIEIO 011111 ----- ----- ----- 1101010110 -
# Branch History Rolling Buffer (BHRB) Instructions
&XFX_bhrbe rt bhrbe
@XFX_bhrbe ...... rt:5 bhrbe:10 .......... - &XFX_bhrbe
MFBHRBE 011111 ..... ..... ..... 0100101110 - @XFX_bhrbe
CLRBHRB 011111 ----- ----- ----- 0110101110 -
## Misc POWER instructions
ATTN 000000 00000 00000 00000 0100000000 0

View File

@ -44,7 +44,7 @@ static inline void helper_update_ov_legacy(CPUPPCState *env, int ov)
} }
} }
target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb, target_ulong helper_DIVWEU(CPUPPCState *env, target_ulong ra, target_ulong rb,
uint32_t oe) uint32_t oe)
{ {
uint64_t rt = 0; uint64_t rt = 0;
@ -71,7 +71,7 @@ target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
return (target_ulong)rt; return (target_ulong)rt;
} }
target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb, target_ulong helper_DIVWE(CPUPPCState *env, target_ulong ra, target_ulong rb,
uint32_t oe) uint32_t oe)
{ {
int64_t rt = 0; int64_t rt = 0;
@ -101,7 +101,7 @@ target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe) uint64_t helper_DIVDEU(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
{ {
uint64_t rt = 0; uint64_t rt = 0;
int overflow = 0; int overflow = 0;
@ -120,7 +120,7 @@ uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
return rt; return rt;
} }
uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe) uint64_t helper_DIVDE(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
{ {
uint64_t rt = 0; uint64_t rt = 0;
int64_t ra = (int64_t)rau; int64_t ra = (int64_t)rau;
@ -159,7 +159,7 @@ uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
/* When you XOR the pattern and there is a match, that byte will be zero */ /* When you XOR the pattern and there is a match, that byte will be zero */
#define hasvalue(x, n) (haszero((x) ^ pattern(n))) #define hasvalue(x, n) (haszero((x) ^ pattern(n)))
uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb) uint32_t helper_CMPEQB(target_ulong ra, target_ulong rb)
{ {
return hasvalue(rb, ra) ? CRF_GT : 0; return hasvalue(rb, ra) ? CRF_GT : 0;
} }
@ -171,7 +171,7 @@ uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb)
/* /*
* Return a random number. * Return a random number.
*/ */
uint64_t helper_darn32(void) uint64_t helper_DARN32(void)
{ {
Error *err = NULL; Error *err = NULL;
uint32_t ret; uint32_t ret;
@ -186,7 +186,7 @@ uint64_t helper_darn32(void)
return ret; return ret;
} }
uint64_t helper_darn64(void) uint64_t helper_DARN64(void)
{ {
Error *err = NULL; Error *err = NULL;
uint64_t ret; uint64_t ret;
@ -201,7 +201,7 @@ uint64_t helper_darn64(void)
return ret; return ret;
} }
uint64_t helper_bpermd(uint64_t rs, uint64_t rb) uint64_t helper_BPERMD(uint64_t rs, uint64_t rb)
{ {
int i; int i;
uint64_t ra = 0; uint64_t ra = 0;
@ -219,7 +219,7 @@ uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
#endif #endif
target_ulong helper_cmpb(target_ulong rs, target_ulong rb) target_ulong helper_CMPB(target_ulong rs, target_ulong rb)
{ {
target_ulong mask = 0xff; target_ulong mask = 0xff;
target_ulong ra = 0; target_ulong ra = 0;
@ -288,7 +288,7 @@ target_ulong helper_srad(CPUPPCState *env, target_ulong value,
#endif #endif
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
target_ulong helper_popcntb(target_ulong val) target_ulong helper_POPCNTB(target_ulong val)
{ {
/* Note that we don't fold past bytes */ /* Note that we don't fold past bytes */
val = (val & 0x5555555555555555ULL) + ((val >> 1) & val = (val & 0x5555555555555555ULL) + ((val >> 1) &
@ -300,7 +300,7 @@ target_ulong helper_popcntb(target_ulong val)
return val; return val;
} }
target_ulong helper_popcntw(target_ulong val) target_ulong helper_POPCNTW(target_ulong val)
{ {
/* Note that we don't fold past words. */ /* Note that we don't fold past words. */
val = (val & 0x5555555555555555ULL) + ((val >> 1) & val = (val & 0x5555555555555555ULL) + ((val >> 1) &
@ -316,7 +316,7 @@ target_ulong helper_popcntw(target_ulong val)
return val; return val;
} }
#else #else
target_ulong helper_popcntb(target_ulong val) target_ulong helper_POPCNTB(target_ulong val)
{ {
/* Note that we don't fold past bytes */ /* Note that we don't fold past bytes */
val = (val & 0x55555555) + ((val >> 1) & 0x55555555); val = (val & 0x55555555) + ((val >> 1) & 0x55555555);

View File

@ -234,51 +234,23 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu);
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
const gchar *ppc_gdb_arch_name(CPUState *cs); const gchar *ppc_gdb_arch_name(CPUState *cs);
/**
* prot_for_access_type:
* @access_type: Access type
*
* Return the protection bit required for the given access type.
*/
static inline int prot_for_access_type(MMUAccessType access_type)
{
switch (access_type) {
case MMU_INST_FETCH:
return PAGE_EXEC;
case MMU_DATA_LOAD:
return PAGE_READ;
case MMU_DATA_STORE:
return PAGE_WRITE;
}
g_assert_not_reached();
}
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/* PowerPC MMU emulation */ /* Check if permission bit required for the access_type is set in prot */
static inline int check_prot_access_type(int prot, MMUAccessType access_type)
{
return prot & (1 << access_type);
}
typedef struct mmu_ctx_t mmu_ctx_t; /* PowerPC MMU emulation */
bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type, bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, hwaddr *raddrp, int *psizep, int *protp,
int mmu_idx, bool guest_visible); int mmu_idx, bool guest_visible);
int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr,
MMUAccessType access_type, int type,
int mmu_idx);
/* Software driven TLB helpers */ /* Software driven TLB helpers */
int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
int way, int is_code); int way, int is_code);
/* Context used internally during MMU translations */
struct mmu_ctx_t {
hwaddr raddr; /* Real address */
hwaddr eaddr; /* Effective address */
int prot; /* Protection bits */
hwaddr hash[2]; /* Pagetable hash values */
target_ulong ptem; /* Virtual segment ID | API */
int key; /* Access key */
int nx; /* Non-execute area */
};
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */

View File

@ -865,9 +865,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu)
sregs.pvr = env->spr[SPR_PVR]; sregs.pvr = env->spr[SPR_PVR];
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = sregs.u.s.sdr1 = cpu->vhyp_class->encode_hpt_for_kvm_pr(cpu->vhyp);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
sregs.u.s.sdr1 = vhc->encode_hpt_for_kvm_pr(cpu->vhyp);
} else { } else {
sregs.u.s.sdr1 = env->spr[SPR_SDR1]; sregs.u.s.sdr1 = env->spr[SPR_SDR1];
} }

View File

@ -333,7 +333,7 @@ static int cpu_post_load(void *opaque, int version_id)
* triggered types (including HDEC) would need to carry more state. * triggered types (including HDEC) would need to carry more state.
*/ */
cpu_ppc_store_decr(env, env->spr[SPR_DECR]); cpu_ppc_store_decr(env, env->spr[SPR_DECR]);
pmu_mmcr01_updated(env); pmu_mmcr01a_updated(env);
} }
return 0; return 0;
@ -711,6 +711,26 @@ static const VMStateDescription vmstate_reservation = {
} }
}; };
#ifdef TARGET_PPC64
static bool bhrb_needed(void *opaque)
{
PowerPCCPU *cpu = opaque;
return (cpu->env.flags & POWERPC_FLAG_BHRB) != 0;
}
static const VMStateDescription vmstate_bhrb = {
.name = "cpu/bhrb",
.version_id = 1,
.minimum_version_id = 1,
.needed = bhrb_needed,
.fields = (VMStateField[]) {
VMSTATE_UINTTL(env.bhrb_offset, PowerPCCPU),
VMSTATE_UINT64_ARRAY(env.bhrb, PowerPCCPU, BHRB_MAX_NUM_ENTRIES),
VMSTATE_END_OF_LIST()
}
};
#endif
const VMStateDescription vmstate_ppc_cpu = { const VMStateDescription vmstate_ppc_cpu = {
.name = "cpu", .name = "cpu",
.version_id = 5, .version_id = 5,
@ -756,6 +776,7 @@ const VMStateDescription vmstate_ppc_cpu = {
#ifdef TARGET_PPC64 #ifdef TARGET_PPC64
&vmstate_tm, &vmstate_tm,
&vmstate_slb, &vmstate_slb,
&vmstate_bhrb,
#endif /* TARGET_PPC64 */ #endif /* TARGET_PPC64 */
&vmstate_tlb6xx, &vmstate_tlb6xx,
&vmstate_tlbemb, &vmstate_tlbemb,

View File

@ -404,9 +404,9 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
} \ } \
} }
#define I(x) (x) #define I(x) (x)
LVE(lvebx, cpu_ldub_data_ra, I, u8) LVE(LVEBX, cpu_ldub_data_ra, I, u8)
LVE(lvehx, cpu_lduw_data_ra, bswap16, u16) LVE(LVEHX, cpu_lduw_data_ra, bswap16, u16)
LVE(lvewx, cpu_ldl_data_ra, bswap32, u32) LVE(LVEWX, cpu_ldl_data_ra, bswap32, u32)
#undef I #undef I
#undef LVE #undef LVE
@ -432,9 +432,9 @@ LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
} \ } \
} }
#define I(x) (x) #define I(x) (x)
STVE(stvebx, cpu_stb_data_ra, I, u8) STVE(STVEBX, cpu_stb_data_ra, I, u8)
STVE(stvehx, cpu_stw_data_ra, bswap16, u16) STVE(STVEHX, cpu_stw_data_ra, bswap16, u16)
STVE(stvewx, cpu_stl_data_ra, bswap32, u32) STVE(STVEWX, cpu_stl_data_ra, bswap32, u32)
#undef I #undef I
#undef LVE #undef LVE

View File

@ -37,6 +37,7 @@ ppc_system_ss.add(files(
'arch_dump.c', 'arch_dump.c',
'machine.c', 'machine.c',
'mmu-hash32.c', 'mmu-hash32.c',
'mmu-booke.c',
'mmu_common.c', 'mmu_common.c',
'ppc-qmp-cmds.c', 'ppc-qmp-cmds.c',
)) ))

View File

@ -150,6 +150,17 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
#ifdef TARGET_PPC64
static void helper_mmcr0_facility_check(CPUPPCState *env, uint32_t bit,
uint32_t sprn, uint32_t cause)
{
if (FIELD_EX64(env->msr, MSR, PR) &&
!(env->spr[SPR_POWER_MMCR0] & (1ULL << bit))) {
raise_fu_exception(env, bit, sprn, cause, GETPC());
}
}
#endif
void helper_store_sdr1(CPUPPCState *env, target_ulong val) void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{ {
if (env->spr[SPR_SDR1] != val) { if (env->spr[SPR_SDR1] != val) {
@ -162,6 +173,7 @@ void helper_store_sdr1(CPUPPCState *env, target_ulong val)
void helper_store_ptcr(CPUPPCState *env, target_ulong val) void helper_store_ptcr(CPUPPCState *env, target_ulong val)
{ {
if (env->spr[SPR_PTCR] != val) { if (env->spr[SPR_PTCR] != val) {
CPUState *cs = env_cpu(env);
PowerPCCPU *cpu = env_archcpu(env); PowerPCCPU *cpu = env_archcpu(env);
target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS; target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS;
target_ulong patbsize = val & PTCR_PATS; target_ulong patbsize = val & PTCR_PATS;
@ -183,8 +195,19 @@ void helper_store_ptcr(CPUPPCState *env, target_ulong val)
return; return;
} }
env->spr[SPR_PTCR] = val; if (cs->nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
tlb_flush(env_cpu(env)); env->spr[SPR_PTCR] = val;
tlb_flush(cs);
} else {
CPUState *ccs;
THREAD_SIBLING_FOREACH(cs, ccs) {
PowerPCCPU *ccpu = POWERPC_CPU(ccs);
CPUPPCState *cenv = &ccpu->env;
cenv->spr[SPR_PTCR] = val;
tlb_flush(ccs);
}
}
} }
} }
@ -284,6 +307,72 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
} }
bql_unlock(); bql_unlock();
} }
/* Indirect SCOM (SPRC/SPRD) access to SCRATCH0-7 are implemented. */
void helper_store_sprc(CPUPPCState *env, target_ulong val)
{
if (val & ~0x3f8ULL) {
qemu_log_mask(LOG_GUEST_ERROR, "Invalid SPRC register value "
TARGET_FMT_lx"\n", val);
return;
}
env->spr[SPR_POWER_SPRC] = val;
}
target_ulong helper_load_sprd(CPUPPCState *env)
{
target_ulong sprc = env->spr[SPR_POWER_SPRC];
switch (sprc & 0x3c0) {
case 0: /* SCRATCH0-7 */
return env->scratch[(sprc >> 3) & 0x7];
default:
qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
break;
}
return 0;
}
static void do_store_scratch(CPUPPCState *env, int nr, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
uint32_t nr_threads = cs->nr_threads;
/*
* Log stores to SCRATCH, because some firmware uses these for debugging
* and logging, but they would normally be read by the BMC, which is
* not implemented in QEMU yet. This gives a way to get at the information.
* Could also dump these upon checkstop.
*/
qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
if (nr_threads == 1) {
env->scratch[nr] = val;
return;
}
THREAD_SIBLING_FOREACH(cs, ccs) {
CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
cenv->scratch[nr] = val;
}
}
void helper_store_sprd(CPUPPCState *env, target_ulong val)
{
target_ulong sprc = env->spr[SPR_POWER_SPRC];
switch (sprc & 0x3c0) {
case 0: /* SCRATCH0-7 */
do_store_scratch(env, (sprc >> 3) & 0x7, val);
break;
default:
qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
break;
}
}
#endif /* defined(TARGET_PPC64) */ #endif /* defined(TARGET_PPC64) */
void helper_store_pidr(CPUPPCState *env, target_ulong val) void helper_store_pidr(CPUPPCState *env, target_ulong val)
@ -363,3 +452,42 @@ void helper_fixup_thrm(CPUPPCState *env)
env->spr[i] = v; env->spr[i] = v;
} }
} }
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
void helper_clrbhrb(CPUPPCState *env)
{
helper_hfscr_facility_check(env, HFSCR_BHRB, "clrbhrb", FSCR_IC_BHRB);
helper_mmcr0_facility_check(env, MMCR0_BHRBA_NR, 0, FSCR_IC_BHRB);
if (env->flags & POWERPC_FLAG_BHRB) {
memset(env->bhrb, 0, sizeof(env->bhrb));
}
}
uint64_t helper_mfbhrbe(CPUPPCState *env, uint32_t bhrbe)
{
unsigned int index;
helper_hfscr_facility_check(env, HFSCR_BHRB, "mfbhrbe", FSCR_IC_BHRB);
helper_mmcr0_facility_check(env, MMCR0_BHRBA_NR, 0, FSCR_IC_BHRB);
if (!(env->flags & POWERPC_FLAG_BHRB) ||
(bhrbe >= env->bhrb_num_entries) ||
(env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE)) {
return 0;
}
/*
* Note: bhrb_offset is the byte offset for writing the
* next entry (over the oldest entry), which is why we
* must offset bhrbe by 1 to get to the 0th entry.
*/
index = ((env->bhrb_offset / sizeof(uint64_t)) - (bhrbe + 1)) %
env->bhrb_num_entries;
return env->bhrb[index];
}
#endif
#endif

View File

@ -108,9 +108,7 @@ static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
uint64_t base; uint64_t base;
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = return cpu->vhyp_class->hpt_mask(cpu->vhyp);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
return vhc->hpt_mask(cpu->vhyp);
} }
if (cpu->env.mmu_model == POWERPC_MMU_3_00) { if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
ppc_v3_pate_t pate; ppc_v3_pate_t pate;

531
target/ppc/mmu-booke.c Normal file
View File

@ -0,0 +1,531 @@
/*
* PowerPC BookE MMU, TLB emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
* 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.1 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/>.
*/
#include "qemu/osdep.h"
#include "exec/page-protection.h"
#include "exec/log.h"
#include "cpu.h"
#include "internal.h"
#include "mmu-booke.h"
/* Generic TLB check function for embedded PowerPC implementations */
static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
hwaddr *raddrp,
target_ulong address, uint32_t pid, int i)
{
target_ulong mask;
/* Check valid flag */
if (!(tlb->prot & PAGE_VALID)) {
return false;
}
mask = ~(tlb->size - 1);
qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
" PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n",
__func__, i, address, pid, tlb->EPN,
mask, (uint32_t)tlb->PID, tlb->prot);
/* Check PID */
if (tlb->PID != 0 && tlb->PID != pid) {
return false;
}
/* Check effective address */
if ((address & mask) != tlb->EPN) {
return false;
}
*raddrp = (tlb->RPN & mask) | (address & ~mask);
return true;
}
/* Generic TLB search function for PowerPC embedded implementations */
int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
{
ppcemb_tlb_t *tlb;
hwaddr raddr;
int i;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb.tlbe[i];
if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) {
return i;
}
}
return -1;
}
int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr, int *prot,
target_ulong address,
MMUAccessType access_type)
{
ppcemb_tlb_t *tlb;
int i, ret, zsel, zpr, pr;
ret = -1;
pr = FIELD_EX64(env->msr, MSR, PR);
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb.tlbe[i];
if (!ppcemb_tlb_check(env, tlb, raddr, address,
env->spr[SPR_40x_PID], i)) {
continue;
}
zsel = (tlb->attr >> 4) & 0xF;
zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
qemu_log_mask(CPU_LOG_MMU,
"%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
__func__, i, zsel, zpr, access_type, tlb->attr);
/* Check execute enable bit */
switch (zpr) {
case 0x2:
if (pr != 0) {
goto check_perms;
}
/* fall through */
case 0x3:
/* All accesses granted */
*prot = PAGE_RWX;
ret = 0;
break;
case 0x0:
if (pr != 0) {
/* Raise Zone protection fault. */
env->spr[SPR_40x_ESR] = 1 << 22;
*prot = 0;
ret = -2;
break;
}
/* fall through */
case 0x1:
check_perms:
/* Check from TLB entry */
*prot = tlb->prot;
if (check_prot_access_type(*prot, access_type)) {
ret = 0;
} else {
env->spr[SPR_40x_ESR] = 0;
ret = -2;
}
break;
}
}
qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
HWADDR_FMT_plx " %d %d\n", __func__,
ret < 0 ? "refused" : "granted", address,
ret < 0 ? 0 : *raddr, *prot, ret);
return ret;
}
static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb,
hwaddr *raddr, target_ulong addr, int i)
{
if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) {
if (!env->nb_pids) {
/* Extend the physical address to 36 bits */
*raddr |= (uint64_t)(tlb->RPN & 0xF) << 32;
}
return true;
} else if (!env->nb_pids) {
return false;
}
if (env->spr[SPR_BOOKE_PID1] &&
ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) {
return true;
}
if (env->spr[SPR_BOOKE_PID2] &&
ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) {
return true;
}
return false;
}
static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
hwaddr *raddr, int *prot, target_ulong address,
MMUAccessType access_type, int i)
{
if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
return -1;
}
/* Check the address space */
if ((access_type == MMU_INST_FETCH ?
FIELD_EX64(env->msr, MSR, IR) :
FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) {
qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
return -1;
}
if (FIELD_EX64(env->msr, MSR, PR)) {
*prot = tlb->prot & 0xF;
} else {
*prot = (tlb->prot >> 4) & 0xF;
}
if (check_prot_access_type(*prot, access_type)) {
qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
return 0;
}
qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
return access_type == MMU_INST_FETCH ? -3 : -2;
}
static int mmubooke_get_physical_address(CPUPPCState *env, hwaddr *raddr,
int *prot, target_ulong address,
MMUAccessType access_type)
{
ppcemb_tlb_t *tlb;
int i, ret = -1;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb.tlbe[i];
ret = mmubooke_check_tlb(env, tlb, raddr, prot, address,
access_type, i);
if (ret != -1) {
break;
}
}
qemu_log_mask(CPU_LOG_MMU,
"%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
" %d %d\n", __func__, ret < 0 ? "refused" : "granted",
address, ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
return ret;
}
hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
{
int tlbm_size;
tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
return 1024ULL << tlbm_size;
}
/* TLB check function for MAS based SoftTLBs */
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
target_ulong address, uint32_t pid)
{
hwaddr mask;
uint32_t tlb_pid;
if (!FIELD_EX64(env->msr, MSR, CM)) {
/* In 32bit mode we can only address 32bit EAs */
address = (uint32_t)address;
}
/* Check valid flag */
if (!(tlb->mas1 & MAS1_VALID)) {
return -1;
}
mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
" PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
__func__, address, pid, tlb->mas1, tlb->mas2, mask,
tlb->mas7_3, tlb->mas8);
/* Check PID */
tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
if (tlb_pid != 0 && tlb_pid != pid) {
return -1;
}
/* Check effective address */
if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
return -1;
}
if (raddrp) {
*raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
}
return 0;
}
static bool is_epid_mmu(int mmu_idx)
{
return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
}
static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
{
uint32_t esr = 0;
if (access_type == MMU_DATA_STORE) {
esr |= ESR_ST;
}
if (is_epid_mmu(mmu_idx)) {
esr |= ESR_EPID;
}
return esr;
}
/*
* Get EPID register given the mmu_idx. If this is regular load,
* construct the EPID access bits from current processor state
*
* Get the effective AS and PR bits and the PID. The PID is returned
* only if EPID load is requested, otherwise the caller must detect
* the correct EPID. Return true if valid EPID is returned.
*/
static bool mmubooke206_get_as(CPUPPCState *env,
int mmu_idx, uint32_t *epid_out,
bool *as_out, bool *pr_out)
{
if (is_epid_mmu(mmu_idx)) {
uint32_t epidr;
if (mmu_idx == PPC_TLB_EPID_STORE) {
epidr = env->spr[SPR_BOOKE_EPSC];
} else {
epidr = env->spr[SPR_BOOKE_EPLC];
}
*epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
*as_out = !!(epidr & EPID_EAS);
*pr_out = !!(epidr & EPID_EPR);
return true;
} else {
*as_out = FIELD_EX64(env->msr, MSR, DS);
*pr_out = FIELD_EX64(env->msr, MSR, PR);
return false;
}
}
/* Check if the tlb found by hashing really matches */
static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
hwaddr *raddr, int *prot,
target_ulong address,
MMUAccessType access_type, int mmu_idx)
{
uint32_t epid;
bool as, pr;
bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
if (!use_epid) {
if (ppcmas_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID]) >= 0) {
goto found_tlb;
}
if (env->spr[SPR_BOOKE_PID1] &&
ppcmas_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID1]) >= 0) {
goto found_tlb;
}
if (env->spr[SPR_BOOKE_PID2] &&
ppcmas_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID2]) >= 0) {
goto found_tlb;
}
} else {
if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
goto found_tlb;
}
}
qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address "
"0x" TARGET_FMT_lx "\n", __func__, address);
return -1;
found_tlb:
/* Check the address space and permissions */
if (access_type == MMU_INST_FETCH) {
/* There is no way to fetch code using epid load */
assert(!use_epid);
as = FIELD_EX64(env->msr, MSR, IR);
}
if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
return -1;
}
*prot = 0;
if (pr) {
if (tlb->mas7_3 & MAS3_UR) {
*prot |= PAGE_READ;
}
if (tlb->mas7_3 & MAS3_UW) {
*prot |= PAGE_WRITE;
}
if (tlb->mas7_3 & MAS3_UX) {
*prot |= PAGE_EXEC;
}
} else {
if (tlb->mas7_3 & MAS3_SR) {
*prot |= PAGE_READ;
}
if (tlb->mas7_3 & MAS3_SW) {
*prot |= PAGE_WRITE;
}
if (tlb->mas7_3 & MAS3_SX) {
*prot |= PAGE_EXEC;
}
}
if (check_prot_access_type(*prot, access_type)) {
qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
return 0;
}
qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
return access_type == MMU_INST_FETCH ? -3 : -2;
}
static int mmubooke206_get_physical_address(CPUPPCState *env, hwaddr *raddr,
int *prot, target_ulong address,
MMUAccessType access_type,
int mmu_idx)
{
ppcmas_tlb_t *tlb;
int i, j, ret = -1;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
int ways = booke206_tlb_ways(env, i);
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbm(env, i, address, j);
if (!tlb) {
continue;
}
ret = mmubooke206_check_tlb(env, tlb, raddr, prot, address,
access_type, mmu_idx);
if (ret != -1) {
goto found_tlb;
}
}
}
found_tlb:
qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
HWADDR_FMT_plx " %d %d\n", __func__,
ret < 0 ? "refused" : "granted", address,
ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
return ret;
}
static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
MMUAccessType access_type, int mmu_idx)
{
uint32_t epid;
bool as, pr;
uint32_t missed_tid = 0;
bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
if (access_type == MMU_INST_FETCH) {
as = FIELD_EX64(env->msr, MSR, IR);
}
env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
env->spr[SPR_BOOKE_MAS3] = 0;
env->spr[SPR_BOOKE_MAS6] = 0;
env->spr[SPR_BOOKE_MAS7] = 0;
/* AS */
if (as) {
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
}
env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
if (!use_epid) {
switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
case MAS4_TIDSELD_PID0:
missed_tid = env->spr[SPR_BOOKE_PID];
break;
case MAS4_TIDSELD_PID1:
missed_tid = env->spr[SPR_BOOKE_PID1];
break;
case MAS4_TIDSELD_PID2:
missed_tid = env->spr[SPR_BOOKE_PID2];
break;
}
env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
} else {
missed_tid = epid;
env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
}
env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
/* next victim logic */
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
env->last_way++;
env->last_way &= booke206_tlb_ways(env, 0) - 1;
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
}
bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
bool guest_visible)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
hwaddr raddr;
int prot, ret;
if (env->mmu_model == POWERPC_MMU_BOOKE206) {
ret = mmubooke206_get_physical_address(env, &raddr, &prot, eaddr,
access_type, mmu_idx);
} else {
ret = mmubooke_get_physical_address(env, &raddr, &prot, eaddr,
access_type);
}
if (ret == 0) {
*raddrp = raddr;
*protp = prot;
*psizep = TARGET_PAGE_BITS;
return true;
} else if (!guest_visible) {
return false;
}
log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
env->error_code = 0;
switch (ret) {
case -1:
/* No matches in page tables or TLB */
if (env->mmu_model == POWERPC_MMU_BOOKE206) {
booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
}
cs->exception_index = (access_type == MMU_INST_FETCH) ?
POWERPC_EXCP_ITLB : POWERPC_EXCP_DTLB;
env->spr[SPR_BOOKE_DEAR] = eaddr;
env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
break;
case -2:
/* Access rights violation */
cs->exception_index = (access_type == MMU_INST_FETCH) ?
POWERPC_EXCP_ISI : POWERPC_EXCP_DSI;
if (access_type != MMU_INST_FETCH) {
env->spr[SPR_BOOKE_DEAR] = eaddr;
env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
}
break;
case -3:
/* No execute protection violation */
cs->exception_index = POWERPC_EXCP_ISI;
env->spr[SPR_BOOKE_ESR] = 0;
break;
}
return false;
}

17
target/ppc/mmu-booke.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef PPC_MMU_BOOKE_H
#define PPC_MMU_BOOKE_H
#include "cpu.h"
int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid);
int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr, int *prot,
target_ulong address,
MMUAccessType access_type);
hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb);
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
target_ulong address, uint32_t pid);
bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
bool guest_visible);
#endif

View File

@ -37,57 +37,6 @@
# define LOG_BATS(...) do { } while (0) # define LOG_BATS(...) do { } while (0)
#endif #endif
struct mmu_ctx_hash32 {
hwaddr raddr; /* Real address */
int prot; /* Protection bits */
int key; /* Access key */
};
static int ppc_hash32_pp_prot(int key, int pp, int nx)
{
int prot;
if (key == 0) {
switch (pp) {
case 0x0:
case 0x1:
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
case 0x3:
prot = PAGE_READ;
break;
default:
abort();
}
} else {
switch (pp) {
case 0x0:
prot = 0;
break;
case 0x1:
case 0x3:
prot = PAGE_READ;
break;
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
default:
abort();
}
}
if (nx == 0) {
prot |= PAGE_EXEC;
}
return prot;
}
static int ppc_hash32_pte_prot(int mmu_idx, static int ppc_hash32_pte_prot(int mmu_idx,
target_ulong sr, ppc_hash_pte32_t pte) target_ulong sr, ppc_hash_pte32_t pte)
{ {
@ -258,7 +207,7 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
} }
*prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ; *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
if (*prot & prot_for_access_type(access_type)) { if (check_prot_access_type(*prot, access_type)) {
*raddr = eaddr; *raddr = eaddr;
return true; return true;
} }
@ -392,7 +341,6 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr pte_offset; hwaddr pte_offset;
ppc_hash_pte32_t pte; ppc_hash_pte32_t pte;
int prot; int prot;
int need_prot;
hwaddr raddr; hwaddr raddr;
/* There are no hash32 large pages. */ /* There are no hash32 large pages. */
@ -406,13 +354,11 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
return true; return true;
} }
need_prot = prot_for_access_type(access_type);
/* 2. Check Block Address Translation entries (BATs) */ /* 2. Check Block Address Translation entries (BATs) */
if (env->nb_BATs != 0) { if (env->nb_BATs != 0) {
raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx); raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
if (raddr != -1) { if (raddr != -1) {
if (need_prot & ~*protp) { if (!check_prot_access_type(*protp, access_type)) {
if (guest_visible) { if (guest_visible) {
if (access_type == MMU_INST_FETCH) { if (access_type == MMU_INST_FETCH) {
cs->exception_index = POWERPC_EXCP_ISI; cs->exception_index = POWERPC_EXCP_ISI;
@ -480,7 +426,7 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
prot = ppc_hash32_pte_prot(mmu_idx, sr, pte); prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
if (need_prot & ~prot) { if (!check_prot_access_type(prot, access_type)) {
/* Access right violation */ /* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
if (guest_visible) { if (guest_visible) {

View File

@ -102,6 +102,51 @@ static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1); stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
} }
static inline int ppc_hash32_pp_prot(bool key, int pp, bool nx)
{
int prot;
if (key == 0) {
switch (pp) {
case 0x0:
case 0x1:
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
case 0x3:
prot = PAGE_READ;
break;
default:
abort();
}
} else {
switch (pp) {
case 0x0:
prot = 0;
break;
case 0x1:
case 0x3:
prot = PAGE_READ;
break;
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
default:
abort();
}
}
if (nx == 0) {
prot |= PAGE_EXEC;
}
return prot;
}
typedef struct { typedef struct {
uint32_t pte0, pte1; uint32_t pte0, pte1;
} ppc_hash_pte32_t; } ppc_hash_pte32_t;

View File

@ -517,9 +517,7 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
const ppc_hash_pte64_t *hptes; const ppc_hash_pte64_t *hptes;
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = return cpu->vhyp_class->map_hptes(cpu->vhyp, ptex, n);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
return vhc->map_hptes(cpu->vhyp, ptex, n);
} }
base = ppc_hash64_hpt_base(cpu); base = ppc_hash64_hpt_base(cpu);
@ -539,9 +537,7 @@ void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
hwaddr ptex, int n) hwaddr ptex, int n)
{ {
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->unmap_hptes(cpu->vhyp, hptes, ptex, n);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->unmap_hptes(cpu->vhyp, hptes, ptex, n);
return; return;
} }
@ -821,9 +817,7 @@ static void ppc_hash64_set_r(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_R; hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_R;
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->hpte_set_r(cpu->vhyp, ptex, pte1);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hpte_set_r(cpu->vhyp, ptex, pte1);
return; return;
} }
base = ppc_hash64_hpt_base(cpu); base = ppc_hash64_hpt_base(cpu);
@ -838,9 +832,7 @@ static void ppc_hash64_set_c(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_C; hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + HPTE64_DW1_C;
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc = cpu->vhyp_class->hpte_set_c(cpu->vhyp, ptex, pte1);
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
vhc->hpte_set_c(cpu->vhyp, ptex, pte1);
return; return;
} }
base = ppc_hash64_hpt_base(cpu); base = ppc_hash64_hpt_base(cpu);
@ -1097,7 +1089,7 @@ bool ppc_hash64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
amr_prot = ppc_hash64_amr_prot(cpu, pte); amr_prot = ppc_hash64_amr_prot(cpu, pte);
prot = exec_prot & pp_prot & amr_prot; prot = exec_prot & pp_prot & amr_prot;
need_prot = prot_for_access_type(access_type); need_prot = check_prot_access_type(PAGE_RWX, access_type);
if (need_prot & ~prot) { if (need_prot & ~prot) {
/* Access right violation */ /* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");

View File

@ -185,7 +185,6 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
int mmu_idx, bool partition_scoped) int mmu_idx, bool partition_scoped)
{ {
CPUPPCState *env = &cpu->env; CPUPPCState *env = &cpu->env;
int need_prot;
/* Check Page Attributes (pte58:59) */ /* Check Page Attributes (pte58:59) */
if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) { if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
@ -210,8 +209,8 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
} }
/* Check if requested access type is allowed */ /* Check if requested access type is allowed */
need_prot = prot_for_access_type(access_type); if (!check_prot_access_type(*prot, access_type)) {
if (need_prot & ~*prot) { /* Page Protected for that Access */ /* Page Protected for that Access */
*fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD : *fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD :
DSISR_PROTFAULT; DSISR_PROTFAULT;
return true; return true;
@ -678,9 +677,7 @@ static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr,
/* Get Partition Table */ /* Get Partition Table */
if (cpu->vhyp) { if (cpu->vhyp) {
PPCVirtualHypervisorClass *vhc; if (!cpu->vhyp_class->get_pate(cpu->vhyp, cpu, lpid, &pate)) {
vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
if (!vhc->get_pate(cpu->vhyp, cpu, lpid, &pate)) {
if (guest_visible) { if (guest_visible) {
ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr, ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr,
DSISR_R_BADCONFIG); DSISR_R_BADCONFIG);

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
#include "internal.h" #include "internal.h"
#include "mmu-book3s-v3.h" #include "mmu-book3s-v3.h"
#include "mmu-radix64.h" #include "mmu-radix64.h"
#include "mmu-booke.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
@ -45,14 +46,8 @@
static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env) static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
{ {
ppc6xx_tlb_t *tlb; ppc6xx_tlb_t *tlb;
int nr, max; int nr, max = 2 * env->nb_tlb;
/* LOG_SWTLB("Invalidate all TLBs\n"); */
/* Invalidate all defined software TLB */
max = env->nb_tlb;
if (env->id_tlbs == 1) {
max *= 2;
}
for (nr = 0; nr < max; nr++) { for (nr = 0; nr < max; nr++) {
tlb = &env->tlb.tlb6[nr]; tlb = &env->tlb.tlb6[nr];
pte_invalidate(&tlb->pte0); pte_invalidate(&tlb->pte0);
@ -308,9 +303,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
switch (env->mmu_model) { switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_6xx:
ppc6xx_tlb_invalidate_virt(env, addr, 0); ppc6xx_tlb_invalidate_virt(env, addr, 0);
if (env->id_tlbs == 1) { ppc6xx_tlb_invalidate_virt(env, addr, 1);
ppc6xx_tlb_invalidate_virt(env, addr, 1);
}
break; break;
case POWERPC_MMU_32B: case POWERPC_MMU_32B:
/* /*
@ -534,7 +527,7 @@ void helper_tlbie_isa300(CPUPPCState *env, target_ulong rb, target_ulong rs,
if (local) { if (local) {
tlb_flush_page(env_cpu(env), addr); tlb_flush_page(env_cpu(env), addr);
} else { } else {
tlb_flush_page_all_cpus(env_cpu(env), addr); tlb_flush_page_all_cpus_synced(env_cpu(env), addr);
} }
return; return;
@ -596,30 +589,6 @@ void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
do_6xx_tlb(env, EPN, 1); do_6xx_tlb(env, EPN, 1);
} }
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
{
mmu_ctx_t ctx;
int nb_BATs;
target_ulong ret = 0;
/*
* We don't have to generate many instances of this instruction,
* as rac is supervisor only.
*
* XXX: FIX THIS: Pretend we have no BAT
*/
nb_BATs = env->nb_BATs;
env->nb_BATs = 0;
if (get_physical_address_wtlb(env, &ctx, addr, 0, ACCESS_INT, 0) == 0) {
ret = ctx.raddr;
}
env->nb_BATs = nb_BATs;
return ret;
}
static inline target_ulong booke_tlb_to_page_size(int size) static inline target_ulong booke_tlb_to_page_size(int size)
{ {
return 1024 << (2 * size); return 1024 << (2 * size);

View File

@ -175,6 +175,11 @@ void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
gen_store_spr(SPR_POWER_MMCR2, masked_gprn); gen_store_spr(SPR_POWER_MMCR2, masked_gprn);
} }
void spr_write_MMCRA(DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_mmcrA(tcg_env, cpu_gpr[gprn]);
}
void spr_read_PMC(DisasContext *ctx, int gprn, int sprn) void spr_read_PMC(DisasContext *ctx, int gprn, int sprn)
{ {
TCGv_i32 t_sprn = tcg_constant_i32(sprn); TCGv_i32 t_sprn = tcg_constant_i32(sprn);

View File

@ -82,7 +82,38 @@ static void pmu_update_summaries(CPUPPCState *env)
env->pmc_cyc_cnt = cyc_cnt; env->pmc_cyc_cnt = cyc_cnt;
} }
void pmu_mmcr01_updated(CPUPPCState *env) static void hreg_bhrb_filter_update(CPUPPCState *env)
{
target_long ifm;
if (!(env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE)) {
/* disable recording to BHRB */
env->bhrb_filter = BHRB_TYPE_NORECORD;
return;
}
ifm = (env->spr[SPR_POWER_MMCRA] & MMCRA_IFM_MASK) >> MMCRA_IFM_SHIFT;
switch (ifm) {
case 0:
/* record all branches */
env->bhrb_filter = -1;
break;
case 1:
/* only record calls (LK = 1) */
env->bhrb_filter = BHRB_TYPE_CALL;
break;
case 2:
/* only record indirect branches */
env->bhrb_filter = BHRB_TYPE_INDIRECT;
break;
case 3:
/* only record conditional branches */
env->bhrb_filter = BHRB_TYPE_COND;
break;
}
}
void pmu_mmcr01a_updated(CPUPPCState *env)
{ {
PowerPCCPU *cpu = env_archcpu(env); PowerPCCPU *cpu = env_archcpu(env);
@ -95,6 +126,8 @@ void pmu_mmcr01_updated(CPUPPCState *env)
ppc_set_irq(cpu, PPC_INTERRUPT_PERFM, 0); ppc_set_irq(cpu, PPC_INTERRUPT_PERFM, 0);
} }
hreg_bhrb_filter_update(env);
/* /*
* Should this update overflow timers (if mmcr0 is updated) so they * Should this update overflow timers (if mmcr0 is updated) so they
* get set in cpu_post_load? * get set in cpu_post_load?
@ -260,7 +293,7 @@ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
env->spr[SPR_POWER_MMCR0] = value; env->spr[SPR_POWER_MMCR0] = value;
pmu_mmcr01_updated(env); pmu_mmcr01a_updated(env);
/* Update cycle overflow timers with the current MMCR0 state */ /* Update cycle overflow timers with the current MMCR0 state */
pmu_update_overflow_timers(env); pmu_update_overflow_timers(env);
@ -272,7 +305,14 @@ void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
env->spr[SPR_POWER_MMCR1] = value; env->spr[SPR_POWER_MMCR1] = value;
pmu_mmcr01_updated(env); pmu_mmcr01a_updated(env);
}
void helper_store_mmcrA(CPUPPCState *env, uint64_t value)
{
env->spr[SPR_POWER_MMCRA] = value;
pmu_mmcr01a_updated(env);
} }
target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn) target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn)
@ -301,7 +341,7 @@ static void perfm_alert(PowerPCCPU *cpu)
env->spr[SPR_POWER_MMCR0] |= MMCR0_FC; env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
/* Changing MMCR0_FC requires summaries and hflags update */ /* Changing MMCR0_FC requires summaries and hflags update */
pmu_mmcr01_updated(env); pmu_mmcr01a_updated(env);
/* /*
* Delete all pending timers if we need to freeze * Delete all pending timers if we need to freeze

View File

@ -13,15 +13,22 @@
#ifndef POWER8_PMU_H #ifndef POWER8_PMU_H
#define POWER8_PMU_H #define POWER8_PMU_H
#define BHRB_TYPE_NORECORD 0x00
#define BHRB_TYPE_CALL 0x01
#define BHRB_TYPE_INDIRECT 0x02
#define BHRB_TYPE_COND 0x04
#define BHRB_TYPE_OTHER 0x08
#define BHRB_TYPE_XL_FORM 0x10
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL #define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL
void cpu_ppc_pmu_init(CPUPPCState *env); void cpu_ppc_pmu_init(CPUPPCState *env);
void pmu_mmcr01_updated(CPUPPCState *env); void pmu_mmcr01a_updated(CPUPPCState *env);
#else #else
static inline void cpu_ppc_pmu_init(CPUPPCState *env) { } static inline void cpu_ppc_pmu_init(CPUPPCState *env) { }
static inline void pmu_mmcr01_updated(CPUPPCState *env) { } static inline void pmu_mmcr01a_updated(CPUPPCState *env) { }
#endif #endif
#endif #endif

View File

@ -83,8 +83,11 @@ void spr_read_generic(DisasContext *ctx, int gprn, int sprn);
void spr_write_generic(DisasContext *ctx, int sprn, int gprn); void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
void spr_write_generic32(DisasContext *ctx, int sprn, int gprn); void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
void spr_core_write_generic(DisasContext *ctx, int sprn, int gprn); void spr_core_write_generic(DisasContext *ctx, int sprn, int gprn);
void spr_core_write_generic32(DisasContext *ctx, int sprn, int gprn);
void spr_core_lpar_write_generic(DisasContext *ctx, int sprn, int gprn);
void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn); void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn);
void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn); void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn);
void spr_write_MMCRA(DisasContext *ctx, int sprn, int gprn);
void spr_write_PMC(DisasContext *ctx, int sprn, int gprn); void spr_write_PMC(DisasContext *ctx, int sprn, int gprn);
void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn); void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn);
void spr_read_xer(DisasContext *ctx, int gprn, int sprn); void spr_read_xer(DisasContext *ctx, int gprn, int sprn);
@ -202,6 +205,11 @@ void spr_read_tfmr(DisasContext *ctx, int gprn, int sprn);
void spr_write_tfmr(DisasContext *ctx, int sprn, int gprn); void spr_write_tfmr(DisasContext *ctx, int sprn, int gprn);
void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn); void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn);
void spr_read_dexcr_ureg(DisasContext *ctx, int gprn, int sprn); void spr_read_dexcr_ureg(DisasContext *ctx, int gprn, int sprn);
void spr_read_ppr32(DisasContext *ctx, int sprn, int gprn);
void spr_write_ppr32(DisasContext *ctx, int sprn, int gprn);
void spr_write_sprc(DisasContext *ctx, int sprn, int gprn);
void spr_read_sprd(DisasContext *ctx, int sprn, int gprn);
void spr_write_sprd(DisasContext *ctx, int sprn, int gprn);
#endif #endif
void register_low_BATs(CPUPPCState *env); void register_low_BATs(CPUPPCState *env);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/*
* Power ISA Decode For BHRB Instructions
*
* Copyright IBM Corp. 2023
*
* Authors:
* Glenn Miles <milesg@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
static bool trans_MFBHRBE(DisasContext *ctx, arg_XFX_bhrbe *arg)
{
REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
TCGv_i32 bhrbe = tcg_constant_i32(arg->bhrbe);
gen_helper_mfbhrbe(cpu_gpr[arg->rt], tcg_env, bhrbe);
return true;
}
static bool trans_CLRBHRB(DisasContext *ctx, arg_CLRBHRB *arg)
{
REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
gen_helper_clrbhrb(tcg_env);
return true;
}
#else
static bool trans_MFBHRBE(DisasContext *ctx, arg_XFX_bhrbe *arg)
{
gen_invalid(ctx);
return true;
}
static bool trans_CLRBHRB(DisasContext *ctx, arg_CLRBHRB *arg)
{
gen_invalid(ctx);
return true;
}
#endif

View File

@ -17,7 +17,7 @@ static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg)
REQUIRE_INSNS_FLAGS2(ctx, ISA207S); REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
translator_io_start(&ctx->base); translator_io_start(&ctx->base);
gen_update_cfar(ctx, ctx->cia); gen_update_branch_history(ctx, ctx->cia, NULL, BHRB_TYPE_NORECORD);
gen_helper_rfebb(tcg_env, cpu_gpr[arg->s]); gen_helper_rfebb(tcg_env, cpu_gpr[arg->s]);
ctx->base.is_jmp = DISAS_CHAIN; ctx->base.is_jmp = DISAS_CHAIN;

View File

@ -289,6 +289,50 @@ TRANS(CMPL, do_cmp_X, false);
TRANS(CMPI, do_cmp_D, true); TRANS(CMPI, do_cmp_D, true);
TRANS(CMPLI, do_cmp_D, false); TRANS(CMPLI, do_cmp_D, false);
static bool trans_CMPRB(DisasContext *ctx, arg_CMPRB *a)
{
TCGv_i32 src1 = tcg_temp_new_i32();
TCGv_i32 src2 = tcg_temp_new_i32();
TCGv_i32 src2lo = tcg_temp_new_i32();
TCGv_i32 src2hi = tcg_temp_new_i32();
TCGv_i32 crf = cpu_crf[a->bf];
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
tcg_gen_trunc_tl_i32(src1, cpu_gpr[a->ra]);
tcg_gen_trunc_tl_i32(src2, cpu_gpr[a->rb]);
tcg_gen_andi_i32(src1, src1, 0xFF);
tcg_gen_ext8u_i32(src2lo, src2);
tcg_gen_extract_i32(src2hi, src2, 8, 8);
tcg_gen_setcond_i32(TCG_COND_LEU, src2lo, src2lo, src1);
tcg_gen_setcond_i32(TCG_COND_LEU, src2hi, src1, src2hi);
tcg_gen_and_i32(crf, src2lo, src2hi);
if (a->l) {
tcg_gen_extract_i32(src2lo, src2, 16, 8);
tcg_gen_extract_i32(src2hi, src2, 24, 8);
tcg_gen_setcond_i32(TCG_COND_LEU, src2lo, src2lo, src1);
tcg_gen_setcond_i32(TCG_COND_LEU, src2hi, src1, src2hi);
tcg_gen_and_i32(src2lo, src2lo, src2hi);
tcg_gen_or_i32(crf, crf, src2lo);
}
tcg_gen_shli_i32(crf, crf, CRF_GT_BIT);
return true;
}
static bool trans_CMPEQB(DisasContext *ctx, arg_CMPEQB *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
gen_helper_CMPEQB(cpu_crf[a->bf], cpu_gpr[a->ra], cpu_gpr[a->rb]);
#else
qemu_build_not_reached();
#endif
return true;
}
/* /*
* Fixed-Point Arithmetic Instructions * Fixed-Point Arithmetic Instructions
*/ */
@ -395,6 +439,389 @@ TRANS(SUBFE, do_subf_XO, true, true)
TRANS(SUBFME, do_subf_const_XO, tcg_constant_tl(-1LL), true, true) TRANS(SUBFME, do_subf_const_XO, tcg_constant_tl(-1LL), true, true)
TRANS(SUBFZE, do_subf_const_XO, tcg_constant_tl(0), true, true) TRANS(SUBFZE, do_subf_const_XO, tcg_constant_tl(0), true, true)
static bool trans_MULLI(DisasContext *ctx, arg_MULLI *a)
{
tcg_gen_muli_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
return true;
}
static bool trans_MULLW(DisasContext *ctx, arg_MULLW *a)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
tcg_gen_ext32s_tl(t0, cpu_gpr[a->ra]);
tcg_gen_ext32s_tl(t1, cpu_gpr[a->rb]);
tcg_gen_mul_tl(cpu_gpr[a->rt], t0, t1);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
return true;
}
static bool trans_MULLWO(DisasContext *ctx, arg_MULLWO *a)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
#if defined(TARGET_PPC64)
tcg_gen_ext32s_i64(t0, cpu_gpr[a->ra]);
tcg_gen_ext32s_i64(t1, cpu_gpr[a->rb]);
tcg_gen_mul_i64(cpu_gpr[a->rt], t0, t1);
tcg_gen_sextract_i64(t0, cpu_gpr[a->rt], 31, 1);
tcg_gen_sari_i64(t1, cpu_gpr[a->rt], 32);
#else
tcg_gen_muls2_i32(cpu_gpr[a->rt], t1, cpu_gpr[a->ra], cpu_gpr[a->rb]);
tcg_gen_sari_i32(t0, cpu_gpr[a->rt], 31);
#endif
tcg_gen_setcond_tl(TCG_COND_NE, cpu_ov, t0, t1);
if (is_isa300(ctx)) {
tcg_gen_mov_tl(cpu_ov32, cpu_ov);
}
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
return true;
}
static bool do_mulhw(DisasContext *ctx, arg_XO_tab_rc *a,
void (*helper)(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1,
TCGv_i32 arg2))
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t0, cpu_gpr[a->ra]);
tcg_gen_trunc_tl_i32(t1, cpu_gpr[a->rb]);
helper(t0, t1, t0, t1);
tcg_gen_extu_i32_tl(cpu_gpr[a->rt], t1);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
return true;
}
TRANS(MULHW, do_mulhw, tcg_gen_muls2_i32)
TRANS(MULHWU, do_mulhw, tcg_gen_mulu2_i32)
static bool do_divw(DisasContext *ctx, arg_XO *a, int sign)
{
gen_op_arith_divw(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
sign, a->oe, a->rc);
return true;
}
static bool do_dive(DisasContext *ctx, arg_XO *a,
void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv, TCGv_i32))
{
REQUIRE_INSNS_FLAGS2(ctx, DIVE_ISA206);
helper(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->ra], cpu_gpr[a->rb],
tcg_constant_i32(a->oe));
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
return true;
}
TRANS(DIVW, do_divw, 1);
TRANS(DIVWU, do_divw, 0);
TRANS(DIVWE, do_dive, gen_helper_DIVWE);
TRANS(DIVWEU, do_dive, gen_helper_DIVWEU);
static bool do_modw(DisasContext *ctx, arg_X *a, bool sign)
{
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
gen_op_arith_modw(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
sign);
return true;
}
TRANS(MODUW, do_modw, false);
TRANS(MODSW, do_modw, true);
static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
{
if (a->oe) {
TCGv zero = tcg_constant_tl(0);
gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], zero,
false, false, true, a->rc);
} else {
tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->ra]);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
}
return true;
}
static bool trans_DARN(DisasContext *ctx, arg_DARN *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
if (a->l > 2) {
tcg_gen_movi_i64(cpu_gpr[a->rt], -1);
} else {
translator_io_start(&ctx->base);
if (a->l == 0) {
gen_helper_DARN32(cpu_gpr[a->rt]);
} else {
/* Return 64-bit random for both CRN and RRN */
gen_helper_DARN64(cpu_gpr[a->rt]);
}
}
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_MULLD(DisasContext *ctx, arg_MULLD *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
tcg_gen_mul_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb]);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_MULLDO(DisasContext *ctx, arg_MULLD *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_muls2_i64(t0, t1, cpu_gpr[a->ra], cpu_gpr[a->rb]);
tcg_gen_mov_i64(cpu_gpr[a->rt], t0);
tcg_gen_sari_i64(t0, t0, 63);
tcg_gen_setcond_i64(TCG_COND_NE, cpu_ov, t0, t1);
if (is_isa300(ctx)) {
tcg_gen_mov_tl(cpu_ov32, cpu_ov);
}
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
#else
qemu_build_not_reached();
#endif
return true;
}
static bool do_mulhd(DisasContext *ctx, arg_XO_tab_rc *a,
void (*helper)(TCGv, TCGv, TCGv, TCGv))
{
TCGv lo = tcg_temp_new();
helper(lo, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb]);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
}
return true;
}
TRANS64(MULHD, do_mulhd, tcg_gen_muls2_tl);
TRANS64(MULHDU, do_mulhd, tcg_gen_mulu2_tl);
static bool trans_MADDLD(DisasContext *ctx, arg_MADDLD *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_mul_i64(t1, cpu_gpr[a->vra], cpu_gpr[a->vrb]);
tcg_gen_add_i64(cpu_gpr[a->vrt], t1, cpu_gpr[a->rc]);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_MADDHD(DisasContext *ctx, arg_MADDHD *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
TCGv_i64 lo = tcg_temp_new_i64();
TCGv_i64 hi = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_muls2_i64(lo, hi, cpu_gpr[a->vra], cpu_gpr[a->vrb]);
tcg_gen_sari_i64(t1, cpu_gpr[a->rc], 63);
tcg_gen_add2_i64(t1, cpu_gpr[a->vrt], lo, hi, cpu_gpr[a->rc], t1);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_MADDHDU(DisasContext *ctx, arg_MADDHDU *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
TCGv_i64 lo = tcg_temp_new_i64();
TCGv_i64 hi = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_mulu2_i64(lo, hi, cpu_gpr[a->vra], cpu_gpr[a->vrb]);
tcg_gen_add2_i64(t1, cpu_gpr[a->vrt], lo, hi, cpu_gpr[a->rc],
tcg_constant_i64(0));
#else
qemu_build_not_reached();
#endif
return true;
}
static bool do_divd(DisasContext *ctx, arg_XO *a, bool sign)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
gen_op_arith_divd(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
sign, a->oe, a->rc);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool do_modd(DisasContext *ctx, arg_X *a, bool sign)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
gen_op_arith_modd(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb],
sign);
#else
qemu_build_not_reached();
#endif
return true;
}
TRANS64(DIVD, do_divd, true);
TRANS64(DIVDU, do_divd, false);
static bool trans_DIVDE(DisasContext *ctx, arg_DIVDE *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
return do_dive(ctx, a, gen_helper_DIVDE);
#else
qemu_build_not_reached();
#endif
}
static bool trans_DIVDEU(DisasContext *ctx, arg_DIVDEU *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
return do_dive(ctx, a, gen_helper_DIVDEU);
#else
qemu_build_not_reached();
#endif
return true;
}
TRANS64(MODSD, do_modd, true);
TRANS64(MODUD, do_modd, false);
/*
* Fixed-Point Select Instructions
*/
static bool trans_ISEL(DisasContext *ctx, arg_ISEL *a)
{
REQUIRE_INSNS_FLAGS(ctx, ISEL);
uint32_t bi = a->bc;
uint32_t mask = 0x08 >> (bi & 0x03);
TCGv t0 = tcg_temp_new();
TCGv zr;
tcg_gen_extu_i32_tl(t0, cpu_crf[bi >> 2]);
tcg_gen_andi_tl(t0, t0, mask);
zr = tcg_constant_tl(0);
tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[a->rt], t0, zr,
a->ra ? cpu_gpr[a->ra] : zr,
cpu_gpr[a->rb]);
return true;
}
/*
* Fixed-Point Trap Instructions
*/
static bool trans_TW(DisasContext *ctx, arg_TW *a)
{
TCGv_i32 t0;
if (check_unconditional_trap(ctx, a->rt)) {
return true;
}
t0 = tcg_constant_i32(a->rt);
gen_helper_TW(tcg_env, cpu_gpr[a->ra], cpu_gpr[a->rb], t0);
return true;
}
static bool trans_TWI(DisasContext *ctx, arg_TWI *a)
{
TCGv t0;
TCGv_i32 t1;
if (check_unconditional_trap(ctx, a->rt)) {
return true;
}
t0 = tcg_constant_tl(a->si);
t1 = tcg_constant_i32(a->rt);
gen_helper_TW(tcg_env, cpu_gpr[a->ra], t0, t1);
return true;
}
static bool trans_TD(DisasContext *ctx, arg_TD *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
TCGv_i32 t0;
if (check_unconditional_trap(ctx, a->rt)) {
return true;
}
t0 = tcg_constant_i32(a->rt);
gen_helper_TD(tcg_env, cpu_gpr[a->ra], cpu_gpr[a->rb], t0);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_TDI(DisasContext *ctx, arg_TDI *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
TCGv t0;
TCGv_i32 t1;
if (check_unconditional_trap(ctx, a->rt)) {
return true;
}
t0 = tcg_constant_tl(a->si);
t1 = tcg_constant_i32(a->rt);
gen_helper_TD(tcg_env, cpu_gpr[a->ra], t0, t1);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a) static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
{ {
gen_invalid(ctx); gen_invalid(ctx);
@ -429,6 +856,285 @@ TRANS(SETBCR, do_set_bool_cond, false, true)
TRANS(SETNBC, do_set_bool_cond, true, false) TRANS(SETNBC, do_set_bool_cond, true, false)
TRANS(SETNBCR, do_set_bool_cond, true, true) TRANS(SETNBCR, do_set_bool_cond, true, true)
/*
* Fixed-Point Logical Instructions
*/
static bool do_addi_(DisasContext *ctx, arg_D_ui *a, bool shift)
{
tcg_gen_andi_tl(cpu_gpr[a->ra], cpu_gpr[a->rt], shift ? a->ui << 16 : a->ui);
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
return true;
}
static bool do_ori(DisasContext *ctx, arg_D_ui *a, bool shift)
{
if (a->rt == a->ra && a->ui == 0) {
/* NOP */
return true;
}
tcg_gen_ori_tl(cpu_gpr[a->ra], cpu_gpr[a->rt], shift ? a->ui << 16 : a->ui);
return true;
}
static bool do_xori(DisasContext *ctx, arg_D_ui *a, bool shift)
{
if (a->rt == a->ra && a->ui == 0) {
/* NOP */
return true;
}
tcg_gen_xori_tl(cpu_gpr[a->ra], cpu_gpr[a->rt], shift ? a->ui << 16 : a->ui);
return true;
}
static bool do_logical1(DisasContext *ctx, arg_X_sa_rc *a,
void (*helper)(TCGv, TCGv))
{
helper(cpu_gpr[a->ra], cpu_gpr[a->rs]);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
}
return true;
}
static bool do_logical2(DisasContext *ctx, arg_X_rc *a,
void (*helper)(TCGv, TCGv, TCGv))
{
helper(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
}
return true;
}
static bool trans_OR(DisasContext *ctx, arg_OR *a)
{
/* Optimisation for mr. ri case */
if (a->rt != a->ra || a->rt != a->rb) {
if (a->rt != a->rb) {
tcg_gen_or_tl(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
} else {
tcg_gen_mov_tl(cpu_gpr[a->ra], cpu_gpr[a->rt]);
}
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
}
} else if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->rt]);
#if defined(TARGET_PPC64)
} else if (a->rt != 0) { /* 0 is nop */
int prio = 0;
switch (a->rt) {
case 1:
/* Set process priority to low */
prio = 2;
break;
case 6:
/* Set process priority to medium-low */
prio = 3;
break;
case 2:
/* Set process priority to normal */
prio = 4;
break;
#if !defined(CONFIG_USER_ONLY)
case 31:
if (!ctx->pr) {
/* Set process priority to very low */
prio = 1;
}
break;
case 5:
if (!ctx->pr) {
/* Set process priority to medium-hight */
prio = 5;
}
break;
case 3:
if (!ctx->pr) {
/* Set process priority to high */
prio = 6;
}
break;
case 7:
if (ctx->hv && !ctx->pr) {
/* Set process priority to very high */
prio = 7;
}
break;
#endif
default:
break;
}
if (prio) {
TCGv t0 = tcg_temp_new();
gen_load_spr(t0, SPR_PPR);
tcg_gen_andi_tl(t0, t0, ~0x001C000000000000ULL);
tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50);
gen_store_spr(SPR_PPR, t0);
}
#if !defined(CONFIG_USER_ONLY)
/*
* Pause out of TCG otherwise spin loops with smt_low eat too
* much CPU and the kernel hangs. This applies to all
* encodings other than no-op, e.g., miso(rs=26), yield(27),
* mdoio(29), mdoom(30), and all currently undefined.
*/
gen_pause(ctx);
#endif
#endif
}
return true;
}
static bool trans_XOR(DisasContext *ctx, arg_XOR *a)
{
/* Optimisation for "set to zero" case */
if (a->rt != a->rb) {
tcg_gen_xor_tl(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
} else {
tcg_gen_movi_tl(cpu_gpr[a->ra], 0);
}
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
}
return true;
}
static bool trans_CMPB(DisasContext *ctx, arg_CMPB *a)
{
REQUIRE_INSNS_FLAGS2(ctx, ISA205);
gen_helper_CMPB(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
return true;
}
static bool do_cntzw(DisasContext *ctx, arg_X_sa_rc *a,
void (*helper)(TCGv_i32, TCGv_i32, uint32_t))
{
TCGv_i32 t = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t, cpu_gpr[a->rs]);
helper(t, t, 32);
tcg_gen_extu_i32_tl(cpu_gpr[a->ra], t);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
}
return true;
}
#if defined(TARGET_PPC64)
static bool do_cntzd(DisasContext *ctx, arg_X_sa_rc *a,
void (*helper)(TCGv_i64, TCGv_i64, uint64_t))
{
helper(cpu_gpr[a->ra], cpu_gpr[a->rs], 64);
if (unlikely(a->rc)) {
gen_set_Rc0(ctx, cpu_gpr[a->ra]);
}
return true;
}
#endif
static bool trans_CNTLZD(DisasContext *ctx, arg_CNTLZD *a)
{
REQUIRE_64BIT(ctx);
#if defined(TARGET_PPC64)
do_cntzd(ctx, a, tcg_gen_clzi_i64);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_CNTTZD(DisasContext *ctx, arg_CNTTZD *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
#if defined(TARGET_PPC64)
do_cntzd(ctx, a, tcg_gen_ctzi_i64);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_POPCNTB(DisasContext *ctx, arg_POPCNTB *a)
{
REQUIRE_INSNS_FLAGS(ctx, POPCNTB);
gen_helper_POPCNTB(cpu_gpr[a->ra], cpu_gpr[a->rs]);
return true;
}
static bool trans_POPCNTW(DisasContext *ctx, arg_POPCNTW *a)
{
REQUIRE_INSNS_FLAGS(ctx, POPCNTWD);
#if defined(TARGET_PPC64)
gen_helper_POPCNTW(cpu_gpr[a->ra], cpu_gpr[a->rs]);
#else
tcg_gen_ctpop_i32(cpu_gpr[a->ra], cpu_gpr[a->rs]);
#endif
return true;
}
static bool trans_POPCNTD(DisasContext *ctx, arg_POPCNTD *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS(ctx, POPCNTWD);
#if defined(TARGET_PPC64)
tcg_gen_ctpop_i64(cpu_gpr[a->ra], cpu_gpr[a->rs]);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_PRTYW(DisasContext *ctx, arg_PRTYW *a)
{
TCGv ra = cpu_gpr[a->ra];
TCGv rs = cpu_gpr[a->rs];
TCGv t0 = tcg_temp_new();
REQUIRE_INSNS_FLAGS2(ctx, ISA205);
tcg_gen_shri_tl(t0, rs, 16);
tcg_gen_xor_tl(ra, rs, t0);
tcg_gen_shri_tl(t0, ra, 8);
tcg_gen_xor_tl(ra, ra, t0);
tcg_gen_andi_tl(ra, ra, (target_ulong)0x100000001ULL);
return true;
}
static bool trans_PRTYD(DisasContext *ctx, arg_PRTYD *a)
{
TCGv ra = cpu_gpr[a->ra];
TCGv rs = cpu_gpr[a->rs];
TCGv t0 = tcg_temp_new();
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, ISA205);
tcg_gen_shri_tl(t0, rs, 32);
tcg_gen_xor_tl(ra, rs, t0);
tcg_gen_shri_tl(t0, ra, 16);
tcg_gen_xor_tl(ra, ra, t0);
tcg_gen_shri_tl(t0, ra, 8);
tcg_gen_xor_tl(ra, ra, t0);
tcg_gen_andi_tl(ra, ra, 1);
return true;
}
static bool trans_BPERMD(DisasContext *ctx, arg_BPERMD *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_INSNS_FLAGS2(ctx, PERM_ISA206);
#if defined(TARGET_PPC64)
gen_helper_BPERMD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
#else
qemu_build_not_reached();
#endif
return true;
}
static bool trans_CFUGED(DisasContext *ctx, arg_X *a) static bool trans_CFUGED(DisasContext *ctx, arg_X *a)
{ {
REQUIRE_64BIT(ctx); REQUIRE_64BIT(ctx);
@ -517,6 +1223,27 @@ static bool trans_PEXTD(DisasContext *ctx, arg_X *a)
return true; return true;
} }
TRANS(ANDI_, do_addi_, false);
TRANS(ANDIS_, do_addi_, true);
TRANS(ORI, do_ori, false);
TRANS(ORIS, do_ori, true);
TRANS(XORI, do_xori, false);
TRANS(XORIS, do_xori, true);
TRANS(AND, do_logical2, tcg_gen_and_tl);
TRANS(ANDC, do_logical2, tcg_gen_andc_tl);
TRANS(NAND, do_logical2, tcg_gen_nand_tl);
TRANS(ORC, do_logical2, tcg_gen_orc_tl);
TRANS(NOR, do_logical2, tcg_gen_nor_tl);
TRANS(EQV, do_logical2, tcg_gen_eqv_tl);
TRANS(EXTSB, do_logical1, tcg_gen_ext8s_tl);
TRANS(EXTSH, do_logical1, tcg_gen_ext16s_tl);
TRANS(CNTLZW, do_cntzw, tcg_gen_clzi_i32);
TRANS_FLAGS2(ISA300, CNTTZW, do_cntzw, tcg_gen_ctzi_i32);
TRANS64(EXTSW, do_logical1, tcg_gen_ext32s_tl);
static bool trans_ADDG6S(DisasContext *ctx, arg_X *a) static bool trans_ADDG6S(DisasContext *ctx, arg_X *a)
{ {
const target_ulong carry_bits = (target_ulong)-1 / 0xf; const target_ulong carry_bits = (target_ulong)-1 / 0xf;

View File

@ -30,96 +30,73 @@ static void gen_set_cr1_from_fpscr(DisasContext *ctx)
#endif #endif
/*** Floating-Point arithmetic ***/ /*** Floating-Point arithmetic ***/
#define _GEN_FLOAT_ACB(name, op1, op2, set_fprf, type) \ static bool do_helper_acb(DisasContext *ctx, arg_A *a,
static void gen_f##name(DisasContext *ctx) \ void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64,
{ \ TCGv_i64, TCGv_i64))
TCGv_i64 t0; \ {
TCGv_i64 t1; \ TCGv_i64 t0, t1, t2, t3;
TCGv_i64 t2; \ REQUIRE_INSNS_FLAGS(ctx, FLOAT);
TCGv_i64 t3; \ REQUIRE_FPU(ctx);
if (unlikely(!ctx->fpu_enabled)) { \ t0 = tcg_temp_new_i64();
gen_exception(ctx, POWERPC_EXCP_FPU); \ t1 = tcg_temp_new_i64();
return; \ t2 = tcg_temp_new_i64();
} \ t3 = tcg_temp_new_i64();
t0 = tcg_temp_new_i64(); \ gen_reset_fpstatus();
t1 = tcg_temp_new_i64(); \ get_fpr(t0, a->fra);
t2 = tcg_temp_new_i64(); \ get_fpr(t1, a->frc);
t3 = tcg_temp_new_i64(); \ get_fpr(t2, a->frb);
gen_reset_fpstatus(); \ helper(t3, tcg_env, t0, t1, t2);
get_fpr(t0, rA(ctx->opcode)); \ set_fpr(a->frt, t3);
get_fpr(t1, rC(ctx->opcode)); \ gen_compute_fprf_float64(t3);
get_fpr(t2, rB(ctx->opcode)); \ if (unlikely(a->rc)) {
gen_helper_f##name(t3, tcg_env, t0, t1, t2); \ gen_set_cr1_from_fpscr(ctx);
set_fpr(rD(ctx->opcode), t3); \ }
if (set_fprf) { \ return true;
gen_compute_fprf_float64(t3); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ static bool do_helper_ab(DisasContext *ctx, arg_A_tab *a,
_GEN_FLOAT_ACB(name, 0x3F, op2, set_fprf, type); \ void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64,
_GEN_FLOAT_ACB(name##s, 0x3B, op2, set_fprf, type); TCGv_i64))
{
#define _GEN_FLOAT_AB(name, op1, op2, inval, set_fprf, type) \ TCGv_i64 t0, t1, t2;
static void gen_f##name(DisasContext *ctx) \ REQUIRE_INSNS_FLAGS(ctx, FLOAT);
{ \ REQUIRE_FPU(ctx);
TCGv_i64 t0; \ t0 = tcg_temp_new_i64();
TCGv_i64 t1; \ t1 = tcg_temp_new_i64();
TCGv_i64 t2; \ t2 = tcg_temp_new_i64();
if (unlikely(!ctx->fpu_enabled)) { \ gen_reset_fpstatus();
gen_exception(ctx, POWERPC_EXCP_FPU); \ get_fpr(t0, a->fra);
return; \ get_fpr(t1, a->frb);
} \ helper(t2, tcg_env, t0, t1);
t0 = tcg_temp_new_i64(); \ set_fpr(a->frt, t2);
t1 = tcg_temp_new_i64(); \ gen_compute_fprf_float64(t2);
t2 = tcg_temp_new_i64(); \ if (unlikely(a->rc)) {
gen_reset_fpstatus(); \ gen_set_cr1_from_fpscr(ctx);
get_fpr(t0, rA(ctx->opcode)); \ }
get_fpr(t1, rB(ctx->opcode)); \ return true;
gen_helper_f##name(t2, tcg_env, t0, t1); \
set_fpr(rD(ctx->opcode), t2); \
if (set_fprf) { \
gen_compute_fprf_float64(t2); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AB(name, 0x3F, op2, inval, set_fprf, type); \
_GEN_FLOAT_AB(name##s, 0x3B, op2, inval, set_fprf, type);
#define _GEN_FLOAT_AC(name, op1, op2, inval, set_fprf, type) \ static bool do_helper_ac(DisasContext *ctx, arg_A_tac *a,
static void gen_f##name(DisasContext *ctx) \ void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64,
{ \ TCGv_i64))
TCGv_i64 t0; \ {
TCGv_i64 t1; \ TCGv_i64 t0, t1, t2;
TCGv_i64 t2; \ REQUIRE_INSNS_FLAGS(ctx, FLOAT);
if (unlikely(!ctx->fpu_enabled)) { \ REQUIRE_FPU(ctx);
gen_exception(ctx, POWERPC_EXCP_FPU); \ t0 = tcg_temp_new_i64();
return; \ t1 = tcg_temp_new_i64();
} \ t2 = tcg_temp_new_i64();
t0 = tcg_temp_new_i64(); \ gen_reset_fpstatus();
t1 = tcg_temp_new_i64(); \ get_fpr(t0, a->fra);
t2 = tcg_temp_new_i64(); \ get_fpr(t1, a->frc);
gen_reset_fpstatus(); \ helper(t2, tcg_env, t0, t1);
get_fpr(t0, rA(ctx->opcode)); \ set_fpr(a->frt, t2);
get_fpr(t1, rC(ctx->opcode)); \ gen_compute_fprf_float64(t2);
gen_helper_f##name(t2, tcg_env, t0, t1); \ if (unlikely(a->rc)) {
set_fpr(rD(ctx->opcode), t2); \ gen_set_cr1_from_fpscr(ctx);
if (set_fprf) { \ }
gen_compute_fprf_float64(t2); \ return true;
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AC(name, 0x3F, op2, inval, set_fprf, type); \
_GEN_FLOAT_AC(name##s, 0x3B, op2, inval, set_fprf, type);
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ #define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \ static void gen_f##name(DisasContext *ctx) \
@ -145,64 +122,22 @@ static void gen_f##name(DisasContext *ctx) \
} \ } \
} }
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ static bool do_helper_bs(DisasContext *ctx, arg_A_tb *a,
static void gen_f##name(DisasContext *ctx) \ void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64))
{ \
TCGv_i64 t0; \
TCGv_i64 t1; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
t0 = tcg_temp_new_i64(); \
t1 = tcg_temp_new_i64(); \
gen_reset_fpstatus(); \
get_fpr(t0, rB(ctx->opcode)); \
gen_helper_f##name(t1, tcg_env, t0); \
set_fpr(rD(ctx->opcode), t1); \
if (set_fprf) { \
gen_compute_fprf_float64(t1); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
}
/* fadd - fadds */
GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
/* fdiv - fdivs */
GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
/* fmul - fmuls */
GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
/* fre */
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
/* fres */
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
/* frsqrte */
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
/* frsqrtes */
static void gen_frsqrtes(DisasContext *ctx)
{ {
TCGv_i64 t0; TCGv_i64 t0, t1;
TCGv_i64 t1; REQUIRE_FPU(ctx);
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
t0 = tcg_temp_new_i64(); t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64();
gen_reset_fpstatus(); gen_reset_fpstatus();
get_fpr(t0, rB(ctx->opcode)); get_fpr(t0, a->frb);
gen_helper_frsqrtes(t1, tcg_env, t0); helper(t1, tcg_env, t0);
set_fpr(rD(ctx->opcode), t1); set_fpr(a->frt, t1);
gen_compute_fprf_float64(t1); gen_compute_fprf_float64(t1);
if (unlikely(Rc(ctx->opcode) != 0)) { if (unlikely(a->rc)) {
gen_set_cr1_from_fpscr(ctx); gen_set_cr1_from_fpscr(ctx);
} }
return true;
} }
static bool trans_FSEL(DisasContext *ctx, arg_A *a) static bool trans_FSEL(DisasContext *ctx, arg_A *a)
@ -228,10 +163,6 @@ static bool trans_FSEL(DisasContext *ctx, arg_A *a)
return true; return true;
} }
/* fsub - fsubs */
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
/* Optional: */
static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a, static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a,
void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64)) void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64))
{ {
@ -254,19 +185,33 @@ static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a,
return true; return true;
} }
TRANS(FADD, do_helper_ab, gen_helper_FADD);
TRANS(FADDS, do_helper_ab, gen_helper_FADDS);
TRANS(FSUB, do_helper_ab, gen_helper_FSUB);
TRANS(FSUBS, do_helper_ab, gen_helper_FSUBS);
TRANS(FDIV, do_helper_ab, gen_helper_FDIV);
TRANS(FDIVS, do_helper_ab, gen_helper_FDIVS);
TRANS(FMUL, do_helper_ac, gen_helper_FMUL);
TRANS(FMULS, do_helper_ac, gen_helper_FMULS);
TRANS(FMADD, do_helper_acb, gen_helper_FMADD);
TRANS(FMADDS, do_helper_acb, gen_helper_FMADDS);
TRANS(FMSUB, do_helper_acb, gen_helper_FMSUB);
TRANS(FMSUBS, do_helper_acb, gen_helper_FMSUBS);
TRANS(FNMADD, do_helper_acb, gen_helper_FNMADD);
TRANS(FNMADDS, do_helper_acb, gen_helper_FNMADDS);
TRANS(FNMSUB, do_helper_acb, gen_helper_FNMSUB);
TRANS(FNMSUBS, do_helper_acb, gen_helper_FNMSUBS);
TRANS_FLAGS(FLOAT_EXT, FRE, do_helper_bs, gen_helper_FRE);
TRANS_FLAGS(FLOAT_FRES, FRES, do_helper_bs, gen_helper_FRES);
TRANS_FLAGS(FLOAT_FRSQRTE, FRSQRTE, do_helper_bs, gen_helper_FRSQRTE);
TRANS_FLAGS(FLOAT_FRSQRTES, FRSQRTES, do_helper_bs, gen_helper_FRSQRTES);
TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT);
TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS);
/*** Floating-Point multiply-and-add ***/
/* fmadd - fmadds */
GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
/* fmsub - fmsubs */
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
/* fnmadd - fnmadds */
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
/* fnmsub - fnmsubs */
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
/*** Floating-Point round & convert ***/ /*** Floating-Point round & convert ***/
/* fctiw */ /* fctiw */
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
@ -304,35 +249,30 @@ GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
/* frim */ /* frim */
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
static void gen_ftdiv(DisasContext *ctx) static bool trans_FTDIV(DisasContext *ctx, arg_X_bf *a)
{ {
TCGv_i64 t0; TCGv_i64 t0, t1;
TCGv_i64 t1; REQUIRE_INSNS_FLAGS2(ctx, FP_TST_ISA206);
if (unlikely(!ctx->fpu_enabled)) { REQUIRE_FPU(ctx);
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
t0 = tcg_temp_new_i64(); t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64();
get_fpr(t0, rA(ctx->opcode)); get_fpr(t0, a->ra);
get_fpr(t1, rB(ctx->opcode)); get_fpr(t1, a->rb);
gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1); gen_helper_FTDIV(cpu_crf[a->bf], t0, t1);
return true;
} }
static void gen_ftsqrt(DisasContext *ctx) static bool trans_FTSQRT(DisasContext *ctx, arg_X_bf_b *a)
{ {
TCGv_i64 t0; TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) { REQUIRE_INSNS_FLAGS2(ctx, FP_TST_ISA206);
gen_exception(ctx, POWERPC_EXCP_FPU); REQUIRE_FPU(ctx);
return;
}
t0 = tcg_temp_new_i64(); t0 = tcg_temp_new_i64();
get_fpr(t0, rB(ctx->opcode)); get_fpr(t0, a->rb);
gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0); gen_helper_FTSQRT(cpu_crf[a->bf], t0);
return true;
} }
/*** Floating-Point compare ***/ /*** Floating-Point compare ***/
/* fcmpo */ /* fcmpo */
@ -1111,14 +1051,7 @@ TRANS(STFDX, do_lsfp_X, false, true, false)
TRANS(STFDUX, do_lsfp_X, true, true, false) TRANS(STFDUX, do_lsfp_X, true, true, false)
TRANS(PSTFD, do_lsfp_PLS_D, false, true, false) TRANS(PSTFD, do_lsfp_PLS_D, false, true, false)
#undef _GEN_FLOAT_ACB
#undef GEN_FLOAT_ACB
#undef _GEN_FLOAT_AB
#undef GEN_FLOAT_AB
#undef _GEN_FLOAT_AC
#undef GEN_FLOAT_AC
#undef GEN_FLOAT_B #undef GEN_FLOAT_B
#undef GEN_FLOAT_BS
#undef GEN_LDF #undef GEN_LDF
#undef GEN_LDUF #undef GEN_LDUF

View File

@ -1,36 +1,6 @@
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)
#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \
_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type), \
_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type)
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type), \
_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type)
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type), \
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type)
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ #define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)
GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT),
GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT),
GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT),
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT),
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES),
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE),
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT),
GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT),
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT),
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT),
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT),
GEN_HANDLER_E(ftdiv, 0x3F, 0x00, 0x04, 1, PPC_NONE, PPC2_FP_TST_ISA206),
GEN_HANDLER_E(ftsqrt, 0x3F, 0x00, 0x05, 1, PPC_NONE, PPC2_FP_TST_ISA206),
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT), GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT),
GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT), GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
@ -61,7 +31,6 @@ GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES),
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),

View File

@ -0,0 +1,157 @@
/*
* Power ISA decode for misc instructions
*
* Copyright (c) 2024, IBM Corporation.
*
* 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.1 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/>.
*/
/*
* Memory Barrier Instructions
*/
static bool trans_SYNC(DisasContext *ctx, arg_X_sync *a)
{
TCGBar bar = TCG_MO_ALL;
uint32_t l = a->l;
uint32_t sc = a->sc;
/*
* BookE uses the msync mnemonic. This means hwsync, except in the
* 440, where it an execution serialisation point that requires all
* previous storage accesses to have been performed to memory (which
* doesn't matter for TCG).
*/
if (!(ctx->insns_flags & PPC_MEM_SYNC)) {
if (ctx->insns_flags & PPC_BOOKE) {
tcg_gen_mb(bar | TCG_BAR_SC);
return true;
}
return false;
}
/*
* In ISA v3.1, the L field grew one bit. Mask that out to ignore it in
* older processors. It also added the SC field, zero this to ignore
* it too.
*/
if (!(ctx->insns_flags2 & PPC2_ISA310)) {
l &= 0x3;
sc = 0;
}
if (sc) {
/* Store syncs [stsync, stcisync, stncisync]. These ignore L. */
bar = TCG_MO_ST_ST;
} else {
if (((l == 1) && (ctx->insns_flags2 & PPC2_MEM_LWSYNC)) || (l == 5)) {
/* lwsync, or plwsync on POWER10 and later */
bar = TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST;
}
/*
* We may need to check for a pending TLB flush.
*
* We do this on ptesync (l == 2) on ppc64 and any sync on ppc32.
*
* Additionally, this can only happen in kernel mode however so
* check MSR_PR as well.
*/
if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) {
gen_check_tlb_flush(ctx, true);
}
}
tcg_gen_mb(bar | TCG_BAR_SC);
return true;
}
static bool trans_EIEIO(DisasContext *ctx, arg_EIEIO *a)
{
TCGBar bar = TCG_MO_ALL;
/*
* BookE uses the mbar instruction instead of eieio, which is basically
* full hwsync memory barrier, but is not execution synchronising. For
* the purpose of TCG the distinction is not relevant.
*/
if (!(ctx->insns_flags & PPC_MEM_EIEIO)) {
if ((ctx->insns_flags & PPC_BOOKE) ||
(ctx->insns_flags2 & PPC2_BOOKE206)) {
tcg_gen_mb(bar | TCG_BAR_SC);
return true;
}
return false;
}
/*
* eieio has complex semanitcs. It provides memory ordering between
* operations in the set:
* - loads from CI memory.
* - stores to CI memory.
* - stores to WT memory.
*
* It separately also orders memory for operations in the set:
* - stores to cacheble memory.
*
* It also serializes instructions:
* - dcbt and dcbst.
*
* It separately serializes:
* - tlbie and tlbsync.
*
* And separately serializes:
* - slbieg, slbiag, and slbsync.
*
* The end result is that CI memory ordering requires TCG_MO_ALL
* and it is not possible to special-case more relaxed ordering for
* cacheable accesses. TCG_BAR_SC is required to provide this
* serialization.
*/
/*
* POWER9 has a eieio instruction variant using bit 6 as a hint to
* tell the CPU it is a store-forwarding barrier.
*/
if (ctx->opcode & 0x2000000) {
/*
* ISA says that "Reserved fields in instructions are ignored
* by the processor". So ignore the bit 6 on non-POWER9 CPU but
* as this is not an instruction software should be using,
* complain to the user.
*/
if (!(ctx->insns_flags2 & PPC2_ISA300)) {
qemu_log_mask(LOG_GUEST_ERROR, "invalid eieio using bit 6 at @"
TARGET_FMT_lx "\n", ctx->cia);
} else {
bar = TCG_MO_ST_LD;
}
}
tcg_gen_mb(bar | TCG_BAR_SC);
return true;
}
static bool trans_ATTN(DisasContext *ctx, arg_ATTN *a)
{
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
gen_helper_attn(tcg_env);
return true;
#else
return false;
#endif
}

View File

@ -59,7 +59,7 @@ static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a)
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
if (is_book3s_arch2x(ctx)) { if (is_book3s_arch2x(ctx)) {
gen_helper_book3s_msgsnd(cpu_gpr[a->rb]); gen_helper_book3s_msgsnd(tcg_env, cpu_gpr[a->rb]);
} else { } else {
gen_helper_msgsnd(cpu_gpr[a->rb]); gen_helper_msgsnd(cpu_gpr[a->rb]);
} }

View File

@ -224,6 +224,13 @@ static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local)
a->prs << TLBIE_F_PRS_SHIFT | a->prs << TLBIE_F_PRS_SHIFT |
a->r << TLBIE_F_R_SHIFT | a->r << TLBIE_F_R_SHIFT |
local << TLBIE_F_LOCAL_SHIFT)); local << TLBIE_F_LOCAL_SHIFT));
if (!local) {
/*
* Global TLB flush uses async-work which must run before the
* next instruction, so this must be the last in the TB.
*/
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
}
return true; return true;
#endif #endif

View File

@ -14,125 +14,88 @@ static inline TCGv_ptr gen_avr_ptr(int reg)
return r; return r;
} }
#define GEN_VR_LDX(name, opc2, opc3) \ static bool trans_LVX(DisasContext *ctx, arg_X *a)
static void glue(gen_, name)(DisasContext *ctx) \ {
{ \ TCGv EA;
TCGv EA; \ TCGv_i64 avr;
TCGv_i64 avr; \ REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
if (unlikely(!ctx->altivec_enabled)) { \ REQUIRE_VECTOR(ctx);
gen_exception(ctx, POWERPC_EXCP_VPU); \ gen_set_access_type(ctx, ACCESS_INT);
return; \ avr = tcg_temp_new_i64();
} \ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
gen_set_access_type(ctx, ACCESS_INT); \ tcg_gen_andi_tl(EA, EA, ~0xf);
avr = tcg_temp_new_i64(); \ /*
EA = tcg_temp_new(); \ * We only need to swap high and low halves. gen_qemu_ld64_i64
gen_addr_reg_index(ctx, EA); \ * does necessary 64-bit byteswap already.
tcg_gen_andi_tl(EA, EA, ~0xf); \ */
/* \ gen_qemu_ld64_i64(ctx, avr, EA);
* We only need to swap high and low halves. gen_qemu_ld64_i64 \ set_avr64(a->rt, avr, !ctx->le_mode);
* does necessary 64-bit byteswap already. \ tcg_gen_addi_tl(EA, EA, 8);
*/ \ gen_qemu_ld64_i64(ctx, avr, EA);
if (ctx->le_mode) { \ set_avr64(a->rt, avr, ctx->le_mode);
gen_qemu_ld64_i64(ctx, avr, EA); \ return true;
set_avr64(rD(ctx->opcode), avr, false); \
tcg_gen_addi_tl(EA, EA, 8); \
gen_qemu_ld64_i64(ctx, avr, EA); \
set_avr64(rD(ctx->opcode), avr, true); \
} else { \
gen_qemu_ld64_i64(ctx, avr, EA); \
set_avr64(rD(ctx->opcode), avr, true); \
tcg_gen_addi_tl(EA, EA, 8); \
gen_qemu_ld64_i64(ctx, avr, EA); \
set_avr64(rD(ctx->opcode), avr, false); \
} \
} }
#define GEN_VR_STX(name, opc2, opc3) \
static void gen_st##name(DisasContext *ctx) \
{ \
TCGv EA; \
TCGv_i64 avr; \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_INT); \
avr = tcg_temp_new_i64(); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
tcg_gen_andi_tl(EA, EA, ~0xf); \
/* \
* We only need to swap high and low halves. gen_qemu_st64_i64 \
* does necessary 64-bit byteswap already. \
*/ \
if (ctx->le_mode) { \
get_avr64(avr, rD(ctx->opcode), false); \
gen_qemu_st64_i64(ctx, avr, EA); \
tcg_gen_addi_tl(EA, EA, 8); \
get_avr64(avr, rD(ctx->opcode), true); \
gen_qemu_st64_i64(ctx, avr, EA); \
} else { \
get_avr64(avr, rD(ctx->opcode), true); \
gen_qemu_st64_i64(ctx, avr, EA); \
tcg_gen_addi_tl(EA, EA, 8); \
get_avr64(avr, rD(ctx->opcode), false); \
gen_qemu_st64_i64(ctx, avr, EA); \
} \
}
#define GEN_VR_LVE(name, opc2, opc3, size) \
static void gen_lve##name(DisasContext *ctx) \
{ \
TCGv EA; \
TCGv_ptr rs; \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
if (size > 1) { \
tcg_gen_andi_tl(EA, EA, ~(size - 1)); \
} \
rs = gen_avr_ptr(rS(ctx->opcode)); \
gen_helper_lve##name(tcg_env, rs, EA); \
}
#define GEN_VR_STVE(name, opc2, opc3, size) \
static void gen_stve##name(DisasContext *ctx) \
{ \
TCGv EA; \
TCGv_ptr rs; \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
if (size > 1) { \
tcg_gen_andi_tl(EA, EA, ~(size - 1)); \
} \
rs = gen_avr_ptr(rS(ctx->opcode)); \
gen_helper_stve##name(tcg_env, rs, EA); \
}
GEN_VR_LDX(lvx, 0x07, 0x03);
/* As we don't emulate the cache, lvxl is strictly equivalent to lvx */ /* As we don't emulate the cache, lvxl is strictly equivalent to lvx */
GEN_VR_LDX(lvxl, 0x07, 0x0B); QEMU_FLATTEN
static bool trans_LVXL(DisasContext *ctx, arg_LVXL *a)
{
return trans_LVX(ctx, a);
}
GEN_VR_LVE(bx, 0x07, 0x00, 1); static bool trans_STVX(DisasContext *ctx, arg_STVX *a)
GEN_VR_LVE(hx, 0x07, 0x01, 2); {
GEN_VR_LVE(wx, 0x07, 0x02, 4); TCGv EA;
TCGv_i64 avr;
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
gen_set_access_type(ctx, ACCESS_INT);
avr = tcg_temp_new_i64();
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_andi_tl(EA, EA, ~0xf);
/*
* We only need to swap high and low halves. gen_qemu_st64_i64
* does necessary 64-bit byteswap already.
*/
get_avr64(avr, a->rt, !ctx->le_mode);
gen_qemu_st64_i64(ctx, avr, EA);
tcg_gen_addi_tl(EA, EA, 8);
get_avr64(avr, a->rt, ctx->le_mode);
gen_qemu_st64_i64(ctx, avr, EA);
return true;
}
GEN_VR_STX(svx, 0x07, 0x07);
/* As we don't emulate the cache, stvxl is strictly equivalent to stvx */ /* As we don't emulate the cache, stvxl is strictly equivalent to stvx */
GEN_VR_STX(svxl, 0x07, 0x0F); QEMU_FLATTEN
static bool trans_STVXL(DisasContext *ctx, arg_STVXL *a)
{
return trans_STVX(ctx, a);
}
GEN_VR_STVE(bx, 0x07, 0x04, 1); static bool do_ldst_ve_X(DisasContext *ctx, arg_X *a, int size,
GEN_VR_STVE(hx, 0x07, 0x05, 2); void (*helper)(TCGv_env, TCGv_ptr, TCGv))
GEN_VR_STVE(wx, 0x07, 0x06, 4); {
TCGv EA;
TCGv_ptr vrt;
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
gen_set_access_type(ctx, ACCESS_INT);
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (size > 1) {
tcg_gen_andi_tl(EA, EA, ~(size - 1));
}
vrt = gen_avr_ptr(a->rt);
helper(tcg_env, vrt, EA);
return true;
}
TRANS(LVEBX, do_ldst_ve_X, 1, gen_helper_LVEBX);
TRANS(LVEHX, do_ldst_ve_X, 2, gen_helper_LVEHX);
TRANS(LVEWX, do_ldst_ve_X, 4, gen_helper_LVEWX);
TRANS(STVEBX, do_ldst_ve_X, 1, gen_helper_STVEBX);
TRANS(STVEHX, do_ldst_ve_X, 2, gen_helper_STVEHX);
TRANS(STVEWX, do_ldst_ve_X, 4, gen_helper_STVEWX);
static void gen_mfvscr(DisasContext *ctx) static void gen_mfvscr(DisasContext *ctx)
{ {
@ -242,16 +205,6 @@ static void glue(gen_, name)(DisasContext *ctx) \
16, 16); \ 16, 16); \
} }
/* Logical operations */
GEN_VXFORM_V(vand, MO_64, tcg_gen_gvec_and, 2, 16);
GEN_VXFORM_V(vandc, MO_64, tcg_gen_gvec_andc, 2, 17);
GEN_VXFORM_V(vor, MO_64, tcg_gen_gvec_or, 2, 18);
GEN_VXFORM_V(vxor, MO_64, tcg_gen_gvec_xor, 2, 19);
GEN_VXFORM_V(vnor, MO_64, tcg_gen_gvec_nor, 2, 20);
GEN_VXFORM_V(veqv, MO_64, tcg_gen_gvec_eqv, 2, 26);
GEN_VXFORM_V(vnand, MO_64, tcg_gen_gvec_nand, 2, 22);
GEN_VXFORM_V(vorc, MO_64, tcg_gen_gvec_orc, 2, 21);
#define GEN_VXFORM(name, opc2, opc3) \ #define GEN_VXFORM(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \ static void glue(gen_, name)(DisasContext *ctx) \
{ \ { \
@ -389,22 +342,6 @@ GEN_VXFORM_V(vsububm, MO_8, tcg_gen_gvec_sub, 0, 16);
GEN_VXFORM_V(vsubuhm, MO_16, tcg_gen_gvec_sub, 0, 17); GEN_VXFORM_V(vsubuhm, MO_16, tcg_gen_gvec_sub, 0, 17);
GEN_VXFORM_V(vsubuwm, MO_32, tcg_gen_gvec_sub, 0, 18); GEN_VXFORM_V(vsubuwm, MO_32, tcg_gen_gvec_sub, 0, 18);
GEN_VXFORM_V(vsubudm, MO_64, tcg_gen_gvec_sub, 0, 19); GEN_VXFORM_V(vsubudm, MO_64, tcg_gen_gvec_sub, 0, 19);
GEN_VXFORM_V(vmaxub, MO_8, tcg_gen_gvec_umax, 1, 0);
GEN_VXFORM_V(vmaxuh, MO_16, tcg_gen_gvec_umax, 1, 1);
GEN_VXFORM_V(vmaxuw, MO_32, tcg_gen_gvec_umax, 1, 2);
GEN_VXFORM_V(vmaxud, MO_64, tcg_gen_gvec_umax, 1, 3);
GEN_VXFORM_V(vmaxsb, MO_8, tcg_gen_gvec_smax, 1, 4);
GEN_VXFORM_V(vmaxsh, MO_16, tcg_gen_gvec_smax, 1, 5);
GEN_VXFORM_V(vmaxsw, MO_32, tcg_gen_gvec_smax, 1, 6);
GEN_VXFORM_V(vmaxsd, MO_64, tcg_gen_gvec_smax, 1, 7);
GEN_VXFORM_V(vminub, MO_8, tcg_gen_gvec_umin, 1, 8);
GEN_VXFORM_V(vminuh, MO_16, tcg_gen_gvec_umin, 1, 9);
GEN_VXFORM_V(vminuw, MO_32, tcg_gen_gvec_umin, 1, 10);
GEN_VXFORM_V(vminud, MO_64, tcg_gen_gvec_umin, 1, 11);
GEN_VXFORM_V(vminsb, MO_8, tcg_gen_gvec_smin, 1, 12);
GEN_VXFORM_V(vminsh, MO_16, tcg_gen_gvec_smin, 1, 13);
GEN_VXFORM_V(vminsw, MO_32, tcg_gen_gvec_smin, 1, 14);
GEN_VXFORM_V(vminsd, MO_64, tcg_gen_gvec_smin, 1, 15);
GEN_VXFORM(vmrghb, 6, 0); GEN_VXFORM(vmrghb, 6, 0);
GEN_VXFORM(vmrghh, 6, 1); GEN_VXFORM(vmrghh, 6, 1);
GEN_VXFORM(vmrghw, 6, 2); GEN_VXFORM(vmrghw, 6, 2);
@ -460,15 +397,17 @@ static void trans_vmrgow(DisasContext *ctx)
* Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F. * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F.
* Bytes sh:sh+15 of X are placed into vD. * Bytes sh:sh+15 of X are placed into vD.
*/ */
static void trans_lvsl(DisasContext *ctx) static bool trans_LVSL(DisasContext *ctx, arg_LVSL *a)
{ {
int VT = rD(ctx->opcode);
TCGv_i64 result = tcg_temp_new_i64(); TCGv_i64 result = tcg_temp_new_i64();
TCGv_i64 sh = tcg_temp_new_i64(); TCGv_i64 sh = tcg_temp_new_i64();
TCGv EA = tcg_temp_new(); TCGv EA = tcg_temp_new();
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
/* Get sh(from description) by anding EA with 0xf. */ /* Get sh(from description) by anding EA with 0xf. */
gen_addr_reg_index(ctx, EA); EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_extu_tl_i64(sh, EA); tcg_gen_extu_tl_i64(sh, EA);
tcg_gen_andi_i64(sh, sh, 0xfULL); tcg_gen_andi_i64(sh, sh, 0xfULL);
@ -478,13 +417,14 @@ static void trans_lvsl(DisasContext *ctx)
*/ */
tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL); tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL);
tcg_gen_addi_i64(result, sh, 0x0001020304050607ull); tcg_gen_addi_i64(result, sh, 0x0001020304050607ull);
set_avr64(VT, result, true); set_avr64(a->rt, result, true);
/* /*
* Create bytes sh+8:sh+15 of X(from description) and place them in * Create bytes sh+8:sh+15 of X(from description) and place them in
* lower doubleword of vD. * lower doubleword of vD.
*/ */
tcg_gen_addi_i64(result, sh, 0x08090a0b0c0d0e0fULL); tcg_gen_addi_i64(result, sh, 0x08090a0b0c0d0e0fULL);
set_avr64(VT, result, false); set_avr64(a->rt, result, false);
return true;
} }
/* /*
@ -494,16 +434,17 @@ static void trans_lvsl(DisasContext *ctx)
* Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F. * Let X be the 32-byte value 0x00 || 0x01 || 0x02 || ... || 0x1E || 0x1F.
* Bytes (16-sh):(31-sh) of X are placed into vD. * Bytes (16-sh):(31-sh) of X are placed into vD.
*/ */
static void trans_lvsr(DisasContext *ctx) static bool trans_LVSR(DisasContext *ctx, arg_LVSR *a)
{ {
int VT = rD(ctx->opcode);
TCGv_i64 result = tcg_temp_new_i64(); TCGv_i64 result = tcg_temp_new_i64();
TCGv_i64 sh = tcg_temp_new_i64(); TCGv_i64 sh = tcg_temp_new_i64();
TCGv EA = tcg_temp_new(); TCGv EA = tcg_temp_new();
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
/* Get sh(from description) by anding EA with 0xf. */ /* Get sh(from description) by anding EA with 0xf. */
gen_addr_reg_index(ctx, EA); EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_extu_tl_i64(sh, EA); tcg_gen_extu_tl_i64(sh, EA);
tcg_gen_andi_i64(sh, sh, 0xfULL); tcg_gen_andi_i64(sh, sh, 0xfULL);
@ -513,13 +454,14 @@ static void trans_lvsr(DisasContext *ctx)
*/ */
tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL); tcg_gen_muli_i64(sh, sh, 0x0101010101010101ULL);
tcg_gen_subfi_i64(result, 0x1011121314151617ULL, sh); tcg_gen_subfi_i64(result, 0x1011121314151617ULL, sh);
set_avr64(VT, result, true); set_avr64(a->rt, result, true);
/* /*
* Create bytes (24-sh):(32-sh) of X(from description) and place them in * Create bytes (24-sh):(32-sh) of X(from description) and place them in
* lower doubleword of vD. * lower doubleword of vD.
*/ */
tcg_gen_subfi_i64(result, 0x18191a1b1c1d1e1fULL, sh); tcg_gen_subfi_i64(result, 0x18191a1b1c1d1e1fULL, sh);
set_avr64(VT, result, false); set_avr64(a->rt, result, false);
return true;
} }
/* /*
@ -759,6 +701,37 @@ TRANS_FLAGS(ALTIVEC, VRLH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_rotlv)
TRANS_FLAGS(ALTIVEC, VRLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_rotlv) TRANS_FLAGS(ALTIVEC, VRLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_rotlv)
TRANS_FLAGS2(ALTIVEC_207, VRLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_rotlv) TRANS_FLAGS2(ALTIVEC_207, VRLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_rotlv)
/* Logical operations */
TRANS_FLAGS(ALTIVEC, VAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_and);
TRANS_FLAGS(ALTIVEC, VANDC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_andc);
TRANS_FLAGS(ALTIVEC, VOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_or);
TRANS_FLAGS(ALTIVEC, VXOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_xor);
TRANS_FLAGS(ALTIVEC, VNOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nor);
TRANS_FLAGS2(ALTIVEC_207, VEQV, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_eqv);
TRANS_FLAGS2(ALTIVEC_207, VNAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nand);
TRANS_FLAGS2(ALTIVEC_207, VORC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_orc);
/* Integer Max/Min operations */
TRANS_FLAGS(ALTIVEC, VMAXUB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_umax);
TRANS_FLAGS(ALTIVEC, VMAXUH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_umax);
TRANS_FLAGS(ALTIVEC, VMAXUW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_umax);
TRANS_FLAGS2(ALTIVEC_207, VMAXUD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_umax);
TRANS_FLAGS(ALTIVEC, VMAXSB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_smax);
TRANS_FLAGS(ALTIVEC, VMAXSH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_smax);
TRANS_FLAGS(ALTIVEC, VMAXSW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_smax);
TRANS_FLAGS2(ALTIVEC_207, VMAXSD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_smax);
TRANS_FLAGS(ALTIVEC, VMINUB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_umin);
TRANS_FLAGS(ALTIVEC, VMINUH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_umin);
TRANS_FLAGS(ALTIVEC, VMINUW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_umin);
TRANS_FLAGS2(ALTIVEC_207, VMINUD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_umin);
TRANS_FLAGS(ALTIVEC, VMINSB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_smin);
TRANS_FLAGS(ALTIVEC, VMINSH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_smin);
TRANS_FLAGS(ALTIVEC, VMINSW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_smin);
TRANS_FLAGS2(ALTIVEC_207, VMINSD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_smin);
static TCGv_vec do_vrl_mask_vec(unsigned vece, TCGv_vec vrb) static TCGv_vec do_vrl_mask_vec(unsigned vece, TCGv_vec vrb)
{ {
TCGv_vec t0 = tcg_temp_new_vec_matching(vrb), TCGv_vec t0 = tcg_temp_new_vec_matching(vrb),
@ -1158,8 +1131,6 @@ GEN_VXFORM_TRANS_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
GEN_VXFORM_HETRO(vextubrx, 6, 28) GEN_VXFORM_HETRO(vextubrx, 6, 28)
GEN_VXFORM_HETRO(vextuhrx, 6, 29) GEN_VXFORM_HETRO(vextuhrx, 6, 29)
GEN_VXFORM_HETRO(vextuwrx, 6, 30) GEN_VXFORM_HETRO(vextuwrx, 6, 30)
GEN_VXFORM_TRANS(lvsl, 6, 31)
GEN_VXFORM_TRANS(lvsr, 6, 32)
GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207,
vextuwrx, PPC_NONE, PPC2_ISA300) vextuwrx, PPC_NONE, PPC2_ISA300)
@ -3365,13 +3336,6 @@ TRANS_FLAGS2(ISA310, VMODUQ, do_vx_helper, gen_helper_VMODUQ)
#undef DIVS64 #undef DIVS64
#undef DIVU64 #undef DIVU64
#undef GEN_VR_LDX
#undef GEN_VR_STX
#undef GEN_VR_LVE
#undef GEN_VR_STVE
#undef GEN_VX_LOGICAL
#undef GEN_VX_LOGICAL_207
#undef GEN_VXFORM #undef GEN_VXFORM
#undef GEN_VXFORM_207 #undef GEN_VXFORM_207
#undef GEN_VXFORM_DUAL #undef GEN_VXFORM_DUAL

View File

@ -1,37 +1,3 @@
#define GEN_VR_LDX(name, opc2, opc3) \
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
#define GEN_VR_STX(name, opc2, opc3) \
GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
#define GEN_VR_LVE(name, opc2, opc3) \
GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
#define GEN_VR_STVE(name, opc2, opc3) \
GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
GEN_VR_LDX(lvx, 0x07, 0x03),
GEN_VR_LDX(lvxl, 0x07, 0x0B),
GEN_VR_LVE(bx, 0x07, 0x00),
GEN_VR_LVE(hx, 0x07, 0x01),
GEN_VR_LVE(wx, 0x07, 0x02),
GEN_VR_STX(svx, 0x07, 0x07),
GEN_VR_STX(svxl, 0x07, 0x0F),
GEN_VR_STVE(bx, 0x07, 0x04),
GEN_VR_STVE(hx, 0x07, 0x05),
GEN_VR_STVE(wx, 0x07, 0x06),
#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \
GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16),
GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17),
GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18),
GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19),
GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20),
GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26),
GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22),
GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21),
#define GEN_VXFORM(name, opc2, opc3) \ #define GEN_VXFORM(name, opc2, opc3) \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
@ -67,22 +33,6 @@ GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_DUAL(vsubuwm, bcdus, 0, 18, PPC_ALTIVEC, PPC2_ISA300), GEN_VXFORM_DUAL(vsubuwm, bcdus, 0, 18, PPC_ALTIVEC, PPC2_ISA300),
GEN_VXFORM_DUAL(vsubudm, bcds, 0, 19, PPC2_ALTIVEC_207, PPC2_ISA300), GEN_VXFORM_DUAL(vsubudm, bcds, 0, 19, PPC2_ALTIVEC_207, PPC2_ISA300),
GEN_VXFORM_300(bcds, 0, 27), GEN_VXFORM_300(bcds, 0, 27),
GEN_VXFORM(vmaxub, 1, 0),
GEN_VXFORM(vmaxuh, 1, 1),
GEN_VXFORM(vmaxuw, 1, 2),
GEN_VXFORM_207(vmaxud, 1, 3),
GEN_VXFORM(vmaxsb, 1, 4),
GEN_VXFORM(vmaxsh, 1, 5),
GEN_VXFORM(vmaxsw, 1, 6),
GEN_VXFORM_207(vmaxsd, 1, 7),
GEN_VXFORM(vminub, 1, 8),
GEN_VXFORM(vminuh, 1, 9),
GEN_VXFORM(vminuw, 1, 10),
GEN_VXFORM_207(vminud, 1, 11),
GEN_VXFORM(vminsb, 1, 12),
GEN_VXFORM(vminsh, 1, 13),
GEN_VXFORM(vminsw, 1, 14),
GEN_VXFORM_207(vminsd, 1, 15),
GEN_VXFORM(vmrghb, 6, 0), GEN_VXFORM(vmrghb, 6, 0),
GEN_VXFORM(vmrghh, 6, 1), GEN_VXFORM(vmrghh, 6, 1),
GEN_VXFORM(vmrghw, 6, 2), GEN_VXFORM(vmrghw, 6, 2),