/*
* PowerPC CPU initialization 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 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
*/
/* A lot of PowerPC definition have been included here.
* Most of them are not usable for now but have been kept
* inside "#if defined(TODO) ... #endif" statements to make tests easier.
*/
#include "dis-asm.h"
#include "gdbstub.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
//#define PPC_DUMP_SPR_ACCESSES
#if defined(CONFIG_USER_ONLY)
#define TODO_USER_ONLY 1
#endif
struct ppc_def_t {
const char *name;
uint32_t pvr;
uint32_t svr;
uint64_t insns_flags;
uint64_t msr_mask;
powerpc_mmu_t mmu_model;
powerpc_excp_t excp_model;
powerpc_input_t bus_model;
uint32_t flags;
int bfd_mach;
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
};
/* For user-mode emulation, we don't emulate any IRQ controller */
#if defined(CONFIG_USER_ONLY)
#define PPC_IRQ_INIT_FN(name) \
static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \
{ \
}
#else
#define PPC_IRQ_INIT_FN(name) \
void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
#endif
PPC_IRQ_INIT_FN(40x);
PPC_IRQ_INIT_FN(6xx);
PPC_IRQ_INIT_FN(970);
PPC_IRQ_INIT_FN(e500);
/* Generic callbacks:
* do nothing but store/retrieve spr value
*/
static void spr_read_generic (void *opaque, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], sprn);
#ifdef PPC_DUMP_SPR_ACCESSES
{
TCGv t0 = tcg_const_i32(sprn);
gen_helper_load_dump_spr(t0);
tcg_temp_free_i32(t0);
}
#endif
}
static void spr_write_generic (void *opaque, int sprn, int gprn)
{
gen_store_spr(sprn, cpu_gpr[gprn]);
#ifdef PPC_DUMP_SPR_ACCESSES
{
TCGv t0 = tcg_const_i32(sprn);
gen_helper_store_dump_spr(t0);
tcg_temp_free_i32(t0);
}
#endif
}
#if !defined(CONFIG_USER_ONLY)
static void spr_write_clear (void *opaque, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
gen_load_spr(t0, sprn);
tcg_gen_neg_tl(t1, cpu_gpr[gprn]);
tcg_gen_and_tl(t0, t0, t1);
gen_store_spr(sprn, t0);
tcg_temp_free(t0);
tcg_temp_free(t1);
}
#endif
/* SPR common to all PowerPC */
/* XER */
static void spr_read_xer (void *opaque, int gprn, int sprn)
{
tcg_gen_mov_tl(cpu_gpr[gprn], cpu_xer);
}
static void spr_write_xer (void *opaque, int sprn, int gprn)
{
tcg_gen_mov_tl(cpu_xer, cpu_gpr[gprn]);
}
/* LR */
static void spr_read_lr (void *opaque, int gprn, int sprn)
{
tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr);
}
static void spr_write_lr (void *opaque, int sprn, int gprn)
{
tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
}
/* CTR */
static void spr_read_ctr (void *opaque, int gprn, int sprn)
{
tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr);
}
static void spr_write_ctr (void *opaque, int sprn, int gprn)
{
tcg_gen_mov_tl(cpu_ctr, cpu_gpr[gprn]);
}
/* User read access to SPR */
/* USPRx */
/* UMMCRx */
/* UPMCx */
/* USIA */
/* UDECR */
static void spr_read_ureg (void *opaque, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
}
/* SPR common to all non-embedded PowerPC */
/* DECR */
#if !defined(CONFIG_USER_ONLY)
static void spr_read_decr (void *opaque, int gprn, int sprn)
{
gen_helper_load_decr(cpu_gpr[gprn]);
}
static void spr_write_decr (void *opaque, int sprn, int gprn)
{
gen_helper_store_decr(cpu_gpr[gprn]);
}
#endif
/* SPR common to all non-embedded PowerPC, except 601 */
/* Time base */
static void spr_read_tbl (void *opaque, int gprn, int sprn)
{
gen_helper_load_tbl(cpu_gpr[gprn]);
}
static void spr_read_tbu (void *opaque, int gprn, int sprn)
{
gen_helper_load_tbu(cpu_gpr[gprn]);
}
__attribute__ (( unused ))
static void spr_read_atbl (void *opaque, int gprn, int sprn)
{
gen_helper_load_atbl(cpu_gpr[gprn]);
}
__attribute__ (( unused ))
static void spr_read_atbu (void *opaque, int gprn, int sprn)
{
gen_helper_load_atbu(cpu_gpr[gprn]);
}
#if !defined(CONFIG_USER_ONLY)
static void spr_write_tbl (void *opaque, int sprn, int gprn)
{
gen_helper_store_tbl(cpu_gpr[gprn]);
}
static void spr_write_tbu (void *opaque, int sprn, int gprn)
{
gen_helper_store_tbu(cpu_gpr[gprn]);
}
__attribute__ (( unused ))
static void spr_write_atbl (void *opaque, int sprn, int gprn)
{
gen_helper_store_atbl(cpu_gpr[gprn]);
}
__attribute__ (( unused ))
static void spr_write_atbu (void *opaque, int sprn, int gprn)
{
gen_helper_store_atbu(cpu_gpr[gprn]);
}
#endif
#if !defined(CONFIG_USER_ONLY)
/* IBAT0U...IBAT0U */
/* IBAT0L...IBAT7L */
static void spr_read_ibat (void *opaque, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
}
static void spr_read_ibat_h (void *opaque, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, IBAT[sprn & 1][(sprn - SPR_IBAT4U) / 2]));
}
static void spr_write_ibatu (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
gen_helper_store_ibatu(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatu_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT4U) / 2);
gen_helper_store_ibatu(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatl (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2);
gen_helper_store_ibatl(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatl_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT4L) / 2);
gen_helper_store_ibatl(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
/* DBAT0U...DBAT7U */
/* DBAT0L...DBAT7L */
static void spr_read_dbat (void *opaque, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2]));
}
static void spr_read_dbat_h (void *opaque, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4]));
}
static void spr_write_dbatu (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2);
gen_helper_store_dbatu(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatu_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4);
gen_helper_store_dbatu(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatl (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2);
gen_helper_store_dbatl(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatl_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4);
gen_helper_store_dbatl(t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
/* SDR1 */
static void spr_read_sdr1 (void *opaque, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, sdr1));
}
static void spr_write_sdr1 (void *opaque, int spr