* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "host-utils.h"
-#include "helper.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
#include "helper_regs.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
+#include "exec/cpu_ldst.h"
//#define DEBUG_OP
+static inline bool needs_byteswap(const CPUPPCState *env)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+ return msr_le;
+#else
+ return !msr_le;
+#endif
+}
+
/*****************************************************************************/
/* Memory load and stores */
void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
{
for (; reg < 32; reg++) {
- if (msr_le) {
+ if (needs_byteswap(env)) {
env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
} else {
env->gpr[reg] = cpu_ldl_data(env, addr);
void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
{
for (; reg < 32; reg++) {
- if (msr_le) {
+ if (needs_byteswap(env)) {
cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
} else {
cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
}
}
-void helper_dcbz(CPUPPCState *env, target_ulong addr)
+void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
{
- do_dcbz(env, addr, env->dcache_line_size);
-}
+ int dcbz_size = env->dcache_line_size;
-void helper_dcbz_970(CPUPPCState *env, target_ulong addr)
-{
- if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
- do_dcbz(env, addr, 32);
- } else {
- do_dcbz(env, addr, env->dcache_line_size);
+#if defined(TARGET_PPC64)
+ if (!is_dcbzl &&
+ (env->excp_model == POWERPC_EXCP_970) &&
+ ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+ dcbz_size = 32;
}
+#endif
+
+ /* XXX add e500mc support */
+
+ do_dcbz(env, addr, dcbz_size);
}
void helper_icbi(CPUPPCState *env, target_ulong addr)
#define LO_IDX 0
#endif
+/* We use msr_le to determine index ordering in a vector. However,
+ byteswapping is not simply controlled by msr_le. We also need to take
+ into account endianness of the target. This is done for the little-endian
+ PPC64 user-mode target. */
+
#define LVE(name, access, swap, element) \
void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
target_ulong addr) \
int adjust = HI_IDX*(n_elems - 1); \
int sh = sizeof(r->element[0]) >> 1; \
int index = (addr & 0xf) >> sh; \
- \
if (msr_le) { \
+ index = n_elems - index - 1; \
+ } \
+ \
+ if (needs_byteswap(env)) { \
r->element[LO_IDX ? index : (adjust - index)] = \
swap(access(env, addr)); \
} else { \
int adjust = HI_IDX * (n_elems - 1); \
int sh = sizeof(r->element[0]) >> 1; \
int index = (addr & 0xf) >> sh; \
- \
if (msr_le) { \
+ index = n_elems - index - 1; \
+ } \
+ \
+ if (needs_byteswap(env)) { \
access(env, addr, swap(r->element[LO_IDX ? index : \
(adjust - index)])); \
} else { \
#undef HI_IDX
#undef LO_IDX
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined(CONFIG_USER_ONLY)
-
-#define MMUSUFFIX _mmu
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
- NULL, it means that the function was called in C code (i.e. not
- from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
- uintptr_t retaddr)
+void helper_tbegin(CPUPPCState *env)
{
- TranslationBlock *tb;
- int ret;
+ /* As a degenerate implementation, always fail tbegin. The reason
+ * given is "Nesting overflow". The "persistent" bit is set,
+ * providing a hint to the error handler to not retry. The TFIAR
+ * captures the address of the failure, which is this tbegin
+ * instruction. Instruction execution will continue with the
+ * next instruction in memory, which is precisely what we want.
+ */
- ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
- if (unlikely(ret != 0)) {
- if (likely(retaddr)) {
- /* now we have a real cpu fault */
- tb = tb_find_pc(retaddr);
- if (likely(tb)) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, retaddr);
- }
- }
- helper_raise_exception_err(env, env->exception_index, env->error_code);
- }
+ env->spr[SPR_TEXASR] =
+ (1ULL << TEXASR_FAILURE_PERSISTENT) |
+ (1ULL << TEXASR_NESTING_OVERFLOW) |
+ (msr_hv << TEXASR_PRIVILEGE_HV) |
+ (msr_pr << TEXASR_PRIVILEGE_PR) |
+ (1ULL << TEXASR_FAILURE_SUMMARY) |
+ (1ULL << TEXASR_TFIAR_EXACT);
+ env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr;
+ env->spr[SPR_TFHAR] = env->nip + 4;
+ env->crf[0] = 0xB; /* 0b1010 = transaction failure */
}
-#endif /* !CONFIG_USER_ONLY */