/*
* PowerPC CPU initialization for qemu.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
* Copyright 2011 Freescale Semiconductor, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "disas/bfd.h"
#include "exec/gdbstub.h"
#include <sysemu/kvm.h>
#include "kvm_ppc.h"
#include "sysemu/arch_init.h"
#include "sysemu/cpus.h"
#include "cpu-models.h"
#include "mmu-hash32.h"
#include "mmu-hash64.h"
#include "qemu/error-report.h"
#include "qapi/visitor.h"
#include "hw/qdev-properties.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
//#define PPC_DUMP_SPR_ACCESSES
/* #define USE_APPLE_GDB */
/* 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(POWER7);
PPC_IRQ_INIT_FN(e500);
/* Generic callbacks:
* do nothing but store/retrieve spr value
*/
static void spr_load_dump_spr(int sprn)
{
#ifdef PPC_DUMP_SPR_ACCESSES
TCGv_i32 t0 = tcg_const_i32(sprn);
gen_helper_load_dump_spr(cpu_env, t0);
tcg_temp_free_i32(t0);
#endif
}
static void spr_read_generic (DisasContext *ctx, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], sprn);
spr_load_dump_spr(sprn);
}
static void spr_store_dump_spr(int sprn)
{
#ifdef PPC_DUMP_SPR_ACCESSES
TCGv_i32 t0 = tcg_const_i32(sprn);
gen_helper_store_dump_spr(cpu_env, t0);
tcg_temp_free_i32(t0);
#endif
}
static void spr_write_generic (DisasContext *ctx, int sprn, int gprn)
{
gen_store_spr(sprn, cpu_gpr[gprn]);
spr_store_dump_spr(sprn);
}
#if !defined(CONFIG_USER_ONLY)
static void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
{
#ifdef TARGET_PPC64
TCGv t0 = tcg_temp_new();
tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]);
gen_store_spr(sprn, t0);
tcg_temp_free(t0);
spr_store_dump_spr(sprn);
#else
spr_write_generic(ctx, sprn, gprn);
#endif
}
static void spr_write_clear (DisasContext *ctx, 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);
}
static void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
{
}
#endif
/* SPR common to all PowerPC */
/* XER */
static void spr_read_xer (DisasContext *ctx, int gprn, int sprn)
{
gen_read_xer(cpu_gpr[gprn]);
}
static void spr_write_xer (DisasContext *ctx, int sprn, int gprn)
{
gen_write_xer(cpu_gpr[gprn]);
}
/* LR */
static void spr_read_lr (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr);
}
static void spr_write_lr (DisasContext *ctx, int sprn, int gprn)
{
tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
}
/* CFAR */
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
static void spr_read_cfar (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar);
}
static void spr_write_cfar (DisasContext *ctx, int sprn, int gprn)
{
tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]);
}
#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
/* CTR */
static void spr_read_ctr (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr);
}
static void spr_write_ctr (DisasContext *ctx, 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 (DisasContext *ctx, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
}
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
static void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
{
gen_store_spr(sprn + 0x10, cpu_gpr[gprn]);
}
#endif
/* SPR common to all non-embedded PowerPC */
/* DECR */
#if !defined(CONFIG_USER_ONLY)
static void spr_read_decr (DisasContext *ctx, int gprn, int sprn)
{
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_load_decr(cpu_gpr[gprn], cpu_env);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_stop_exception(ctx);
}
}
static void spr_write_decr (DisasContext *ctx, int sprn, int gprn)
{
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_store_decr(cpu_env, cpu_gpr[gprn]);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_stop_exception(ctx);
}
}
#endif
/* SPR common to all non-embedded PowerPC, except 601 */
/* Time base */
static void spr_read_tbl (DisasContext *ctx, int gprn, int sprn)
{
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_load_tbl(cpu_gpr[gprn], cpu_env);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_stop_exception(ctx);
}
}
static void spr_read_tbu (DisasContext *ctx, int gprn, int sprn)
{
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_load_tbu(cpu_gpr[gprn], cpu_env);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_stop_exception(ctx);
}
}
__attribute__ (( unused ))
static void spr_read_atbl (DisasContext *ctx, int gprn, int sprn)
{
gen_helper_load_atbl(cpu_gpr[gprn], cpu_env);
}
__attribute__ (( unused ))
static void spr_read_atbu (DisasContext *ctx, int gprn, int sprn)
{
gen_helper_load_atbu(cpu_gpr[gprn], cpu_env);
}
#if !defined(CONFIG_USER_ONLY)
static void spr_write_tbl (DisasContext *ctx, int sprn, int gprn)
{
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_stop_exception(ctx);
}
}
static void spr_write_tbu (DisasContext *ctx, int sprn, int gprn)
{
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_stop_exception(ctx);
}
}
__attribute__ (( unused ))
static void spr_write_atbl (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]);
}
__attribute__ (( unused ))
static void spr_write_atbu (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]);
}
#if defined(TARGET_PPC64)
__attribute__ (( unused ))
static void spr_read_purr (DisasContext *ctx, int gprn, int sprn)
{
gen_helper_load_purr(cpu_gpr[gprn], cpu_env);
}
#endif
#endif
#if !defined(CONFIG_USER_ONLY)
/* IBAT0U...IBAT0U */
/* IBAT0L...IBAT7L */
static void spr_read_ibat (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
}
static void spr_read_ibat_h (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, IBAT[sprn & 1][(sprn - SPR_IBAT4U) / 2]));
}
static void spr_write_ibatu (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatu_h (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4);
gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatl (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2);
gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatl_h (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4);
gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
/* DBAT0U...DBAT7U */
/* DBAT0L...DBAT7L */
static void spr_read_dbat (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2]));
}
static void spr_read_dbat_h (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4]));
}
static void spr_write_dbatu (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2);
gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatu_h (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4);
gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatl (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2);
gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatl_h (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4);
gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
/* SDR1 */
static void spr_write_sdr1 (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]);
}
/* 64 bits PowerPC specific SPRs */
#if defined(TARGET_PPC64)
static void spr_read_hior (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix));
}
static void spr_write_hior (DisasContext *ctx, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL);
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
tcg_temp_free(t0);
}
#endif
#endif
/* PowerPC 601 specific registers */
/* RTC */
static void spr_read_601_rtcl (DisasContext *ctx, int gprn, int sprn)
{
gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env);
}
static void spr_read_601_rtcu (DisasContext *ctx, int gprn, int sprn)
{
gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env);
}
#if !defined(CONFIG_USER_ONLY)
static void spr_write_601_rtcu (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_601_rtcl (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_hid0_601 (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
/* Must stop the translation as endianness may have changed */
gen_stop_exception(ctx);
}
#endif
/* Unified bats */
#if !defined(CONFIG_USER_ONLY)
static void spr_read_601_ubat (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
}
static void spr_write_601_ubatu (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_601_ubatl (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
#endif
/* PowerPC 40x specific registers */
#if !defined(CONFIG_USER_ONLY)
static void spr_read_40x_pit (DisasContext *ctx, int gprn, int sprn)
{
gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env);
}
static void spr_write_40x_pit (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_40x_dbcr0 (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
/* We must stop translation as we may have rebooted */
gen_stop_exception(ctx);
}
static void spr_write_40x_sler (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_booke_tcr (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_booke_tsr (DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]);
}
#endif
/* PowerPC 403 specific registers */
/* PBL1 / PBU1 / PBL2 / PBU2 */
#if !defined(CONFIG_USER_ONLY)
static void spr_read_403_pbr (DisasContext *ctx, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1]));
}
static void spr_write_403_pbr (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1);
gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_pir (DisasContext *ctx, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xF);
gen_store_spr(SPR_PIR, t0);
tcg_temp_free(t0);
}
#endif
/* SPE specific registers */
static void spr_read_spefscr (DisasContext *ctx, int gprn, int sprn)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr));
tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0);
tcg_temp_free_i32(t0);
}
static void spr_write_spefscr (DisasContext *ctx, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]);
tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr));
tcg_temp_free_i32(t0);
}
#if !defined(CONFIG_USER_ONLY)
/* Callback used to write the exception vector base */
static void spr_write_excp_prefix (DisasContext *ctx, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivpr_mask));
tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
gen_store_spr(sprn, t0);
tcg_temp_free(t0);
}
static void spr_write_excp_vector (DisasContext *ctx, int sprn, int gprn)
{
int sprn_offs;
if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
sprn_offs = sprn - SPR_BOOKE_IVOR0;
} else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
} else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
} else {
printf("Trying to write an unknown exception vector %d %03x\n",
sprn, sprn);
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
return;
}
TCGv t0 = tcg_temp_new();
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
gen_store_spr(sprn, t0);
tcg_temp_free(t0);
}
#endif
static inline void vscr_init (CPUPPCState *env, uint32_t val)
{
env->vscr = val;
/* Altivec always uses round-to-nearest */
set_float_rounding_mode(float_round_nearest_even, &env->vec_status);
set_flush_to_zero(vscr_nj, &env->vec_status);
}
#ifdef CONFIG_USER_ONLY
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, initial_value)
#else
#if !defined(CONFIG_KVM)
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, initial_value)
#else
#define spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value) \
_spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, one_reg_id, initial_value)
#endif
#endif
#define spr_register(env, num, name, uea_read, uea_write, \
oea_read, oea_write, initial_value) \
spr_register_kvm(env, num, name, uea_read, uea_write, \
oea_read, oea_write, 0, initial_value)
static inline void _spr_register(CPUPPCState *env, int num,
const char *name,
void (*uea_read)(DisasContext *ctx, int gprn, int sprn),
void (*uea_write)(DisasContext *ctx, int sprn, int gprn),
#if !defined(CONFIG_USER_ONLY)
void (*oea_read)(DisasContext *ctx, int gprn, int sprn),
void (*oea_write)(DisasContext *ctx, int sprn, int gprn),
#endif
#if defined(CONFIG_KVM)
uint64_t one_reg_id,
#endif
target_ulong initial_value)
{
ppc_spr_t *spr;
spr = &env->spr_cb[num];
if (spr->name != NULL ||env-> spr[num] != 0x00000000 ||
#if !defined(CONFIG_USER_ONLY)
spr->oea_read != NULL || spr->oea_write != NULL ||
#endif
spr->uea_read != NULL || spr->uea_write != NULL) {
printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
exit(1);
}
#if defined(PPC_DEBUG_SPR)
printf("*** register spr %d (%03x) %s val " TARGET_FMT_lx "\n", num, num,
name, initial_value);
#endif
spr->name = name;
spr->uea_read = uea_read;
spr->uea_write = uea_write;
#if !defined(CONFIG_USER_ONLY)
spr->oea_read = oea_read;
spr->oea_write = oea_write;
#endif
#if defined(CONFIG_KVM)
spr->one_reg_id = one_reg_id,
#endif
env->spr[num] = spr->default_value = initial_value;
}
/* Generic PowerPC SPRs */
static void gen_spr_generic (CPUPPCState *env)
{
/* Integer processing */
spr_register(env, SPR_XER, "XER",
&spr_read_xer, &spr_write_xer,
&spr_read_xer, &spr_write_xer,
0x00000000);
/* Branch contol */
spr_register(env, SPR_LR, "LR",
&spr_read_lr, &spr_write_lr,
&spr_read_lr, &spr_write_lr,
0x00000000);
spr_register(env, SPR_CTR, "CTR",
&spr_read_ctr, &spr_write_ctr,
&spr_read_ctr, &spr_write_ctr,
0x00000000);
/* Interrupt processing */
spr_register(env, SPR_SRR0, "SRR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SRR1, "SRR1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Processor control */
spr_register(env, SPR_SPRG0, "SPRG0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SPRG1, "SPRG1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SPRG2, "SPRG2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SPRG3, "SPRG3",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR common to all non-embedded PowerPC, including 601 */
static void gen_spr_ne_601 (CPUPPCState *env)
{
/* Exception processing */
spr_register_kvm(env, SPR_DSISR, "DSISR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DSISR, 0x00000000);
spr_register_kvm(env, SPR_DAR, "DAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DAR, 0x00000000);
/* Timer */
spr_register(env, SPR_DECR, "DECR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_decr, &spr_write_decr,
0x00000000);
/* Memory management */
spr_register(env, SPR_SDR1, "SDR1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_sdr1,
0x00000000);
}
/* BATs 0-3 */
static void gen_low_BATs (CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register(env, SPR_IBAT0U, "IBAT0U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatu,
0x00000000);
spr_register(env, SPR_IBAT0L, "IBAT0L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatl,
0x00000000);
spr_register(env, SPR_IBAT1U, "IBAT1U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatu,
0x00000000);
spr_register(env, SPR_IBAT1L, "IBAT1L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatl,
0x00000000);
spr_register(env, SPR_IBAT2U, "IBAT2U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatu,
0x00000000);
spr_register(env, SPR_IBAT2L, "IBAT2L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatl,
0x00000000);
spr_register(env, SPR_IBAT3U, "IBAT3U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatu,
0x00000000);
spr_register(env, SPR_IBAT3L, "IBAT3L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat, &spr_write_ibatl,
0x00000000);
spr_register(env, SPR_DBAT0U, "DBAT0U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatu,
0x00000000);
spr_register(env, SPR_DBAT0L, "DBAT0L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatl,
0x00000000);
spr_register(env, SPR_DBAT1U, "DBAT1U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatu,
0x00000000);
spr_register(env, SPR_DBAT1L, "DBAT1L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatl,
0x00000000);
spr_register(env, SPR_DBAT2U, "DBAT2U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatu,
0x00000000);
spr_register(env, SPR_DBAT2L, "DBAT2L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatl,
0x00000000);
spr_register(env, SPR_DBAT3U, "DBAT3U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatu,
0x00000000);
spr_register(env, SPR_DBAT3L, "DBAT3L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat, &spr_write_dbatl,
0x00000000);
env->nb_BATs += 4;
#endif
}
/* BATs 4-7 */
static void gen_high_BATs (CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register(env, SPR_IBAT4U, "IBAT4U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatu_h,
0x00000000);
spr_register(env, SPR_IBAT4L, "IBAT4L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatl_h,
0x00000000);
spr_register(env, SPR_IBAT5U, "IBAT5U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatu_h,
0x00000000);
spr_register(env, SPR_IBAT5L, "IBAT5L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatl_h,
0x00000000);
spr_register(env, SPR_IBAT6U, "IBAT6U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatu_h,
0x00000000);
spr_register(env, SPR_IBAT6L, "IBAT6L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatl_h,
0x00000000);
spr_register(env, SPR_IBAT7U, "IBAT7U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatu_h,
0x00000000);
spr_register(env, SPR_IBAT7L, "IBAT7L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_ibat_h, &spr_write_ibatl_h,
0x00000000);
spr_register(env, SPR_DBAT4U, "DBAT4U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatu_h,
0x00000000);
spr_register(env, SPR_DBAT4L, "DBAT4L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatl_h,
0x00000000);
spr_register(env, SPR_DBAT5U, "DBAT5U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatu_h,
0x00000000);
spr_register(env, SPR_DBAT5L, "DBAT5L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatl_h,
0x00000000);
spr_register(env, SPR_DBAT6U, "DBAT6U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatu_h,
0x00000000);
spr_register(env, SPR_DBAT6L, "DBAT6L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatl_h,
0x00000000);
spr_register(env, SPR_DBAT7U, "DBAT7U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatu_h,
0x00000000);
spr_register(env, SPR_DBAT7L, "DBAT7L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_dbat_h, &spr_write_dbatl_h,
0x00000000);
env->nb_BATs += 4;
#endif
}
/* Generic PowerPC time base */
static void gen_tbl (CPUPPCState *env)
{
spr_register(env, SPR_VTBL, "TBL",
&spr_read_tbl, SPR_NOACCESS,
&spr_read_tbl, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_TBL, "TBL",
&spr_read_tbl, SPR_NOACCESS,
&spr_read_tbl, &spr_write_tbl,
0x00000000);
spr_register(env, SPR_VTBU, "TBU",
&spr_read_tbu, SPR_NOACCESS,
&spr_read_tbu, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_TBU, "TBU",
&spr_read_tbu, SPR_NOACCESS,
&spr_read_tbu, &spr_write_tbu,
0x00000000);
}
/* Softare table search registers */
static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
{
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = nb_tlbs;
env->nb_ways = nb_ways;
env->id_tlbs = 1;
env->tlb_type = TLB_6XX;
spr_register(env, SPR_DMISS, "DMISS",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_DCMP, "DCMP",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_HASH1, "HASH1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_HASH2, "HASH2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_IMISS, "IMISS",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_ICMP, "ICMP",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_RPA, "RPA",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
#endif
}
/* SPR common to MPC755 and G2 */
static void gen_spr_G2_755 (CPUPPCState *env)
{
/* SGPRs */
spr_register(env, SPR_SPRG4, "SPRG4",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SPRG5, "SPRG5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SPRG6, "SPRG6",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_SPRG7, "SPRG7",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR common to all 7xx PowerPC implementations */
static void gen_spr_7xx (CPUPPCState *env)
{
/* Breakpoints */
/* XXX : not implemented */
spr_register_kvm(env, SPR_DABR, "DABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DABR, 0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Cache management */
/* XXX : not implemented */
spr_register(env, SPR_ICTC, "ICTC",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Performance monitors */
/* XXX : not implemented */
spr_register(env, SPR_7XX_MMCR0, "MMCR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_MMCR1, "MMCR1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_PMC1, "PMC1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_PMC2, "PMC2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_PMC3, "PMC3",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_PMC4, "PMC4",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_SIAR, "SIAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_UMMCR0, "UMMCR0",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_UMMCR1, "UMMCR1",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_UPMC1, "UPMC1",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_UPMC2, "UPMC2",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_UPMC3, "UPMC3",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_UPMC4, "UPMC4",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_USIAR, "USIAR",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
#ifdef TARGET_PPC64
#ifndef CONFIG_USER_ONLY
static void spr_read_uamr (DisasContext *ctx, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], SPR_AMR);
spr_load_dump_spr(SPR_AMR);
}
static void spr_write_uamr (DisasContext *ctx, int sprn, int gprn)
{
gen_store_spr(SPR_AMR, cpu_gpr[gprn]);
spr_store_dump_spr(SPR_AMR);
}
static void spr_write_uamr_pr (DisasContext *ctx, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
gen_load_spr(t0, SPR_UAMOR);
tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
gen_store_spr(SPR_AMR, t0);
spr_store_dump_spr(SPR_AMR);
}
#endif /* CONFIG_USER_ONLY */
static void gen_spr_amr (CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
/* Virtual Page Class Key protection */
/* The AMR is accessible either via SPR 13 or SPR 29. 13 is
* userspace accessible, 29 is privileged. So we only need to set
* the kvm ONE_REG id on one of them, we use 29 */
spr_register(env, SPR_UAMR, "UAMR",
&spr_read_uamr, &spr_write_uamr_pr,
&spr_read_uamr, &spr_write_uamr,
0);
spr_register_kvm(env, SPR_AMR, "AMR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_AMR, 0);
spr_register_kvm(env, SPR_UAMOR, "UAMOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_UAMOR, 0);
#endif /* !CONFIG_USER_ONLY */
}
#endif /* TARGET_PPC64 */
static void gen_spr_thrm (CPUPPCState *env)
{
/* Thermal management */
/* XXX : not implemented */
spr_register(env, SPR_THRM1, "THRM1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_THRM2, "THRM2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_THRM3, "THRM3",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR specific to PowerPC 604 implementation */
static void gen_spr_604 (CPUPPCState *env)
{
/* Processor identification */
spr_register(env, SPR_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_pir,
0x00000000);
/* Breakpoints */
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register_kvm(env, SPR_DABR, "DABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DABR, 0x00000000);
/* Performance counters */
/* XXX : not implemented */
spr_register(env, SPR_7XX_MMCR0, "MMCR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_PMC1, "PMC1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_PMC2, "PMC2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_7XX_SIAR, "SIAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_SDA, "SDA",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR specific to PowerPC 603 implementation */
static void gen_spr_603 (CPUPPCState *env)
{
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Breakpoints */
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR specific to PowerPC G2 implementation */
static void gen_spr_G2 (CPUPPCState *env)
{
/* Memory base address */
/* MBAR */
/* XXX : not implemented */
spr_register(env, SPR_MBAR, "MBAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Exception processing */
spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Breakpoints */
/* XXX : not implemented */
spr_register(env, SPR_DABR, "DABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_DABR2, "DABR2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IABR2, "IABR2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IBCR, "IBCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_DBCR, "DBCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR specific to PowerPC 602 implementation */
static void gen_spr_602 (CPUPPCState *env)
{
/* ESA registers */
/* XXX : not implemented */
spr_register(env, SPR_SER, "SER",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_SEBR, "SEBR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_ESASRR, "ESASRR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Floating point status */
/* XXX : not implemented */
spr_register(env, SPR_SP, "SP",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_LT, "LT",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Watchdog timer */
/* XXX : not implemented */
spr_register(env, SPR_TCR, "TCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Interrupt base */
spr_register(env, SPR_IBR, "IBR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
/* SPR specific to PowerPC 601 implementation */
static void gen_spr_601 (CPUPPCState *env)
{
/* Multiplication/division register */
/* MQ */
spr_register(env, SPR_MQ, "MQ",
&spr_read_generic, &spr_write_generic,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* RTC registers */
spr_register(env, SPR_601_RTCU, "RTCU",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, &spr_write_601_rtcu,
0x00000000);
spr_register(env, SPR_601_VRTCU, "RTCU",
&spr_read_601_rtcu, SPR_NOACCESS,
&spr_read_601_rtcu, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_601_RTCL, "RTCL",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, &spr_write_601_rtcl,
0x00000000);
spr_register(env, SPR_601_VRTCL, "RTCL",
&spr_read_601_rtcl, SPR_NOACCESS,
&spr_read_601_rtcl, SPR_NOACCESS,
0x00000000);
/* Timer */
#if 0 /* ? */
spr_register(env, SPR_601_UDECR, "UDECR",
&spr_read_decr, SPR_NOACCESS,
&spr_read_decr, SPR_NOACCESS,
0x00000000);
#endif
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
#if !defined(CONFIG_USER_ONLY)
spr_register(env, SPR_IBAT0U, "IBAT0U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatu,
0x00000000);
spr_register(env, SPR_IBAT0L, "IBAT0L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatl,
0x00000000);
spr_register(env, SPR_IBAT1U, "IBAT1U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatu,
0x00000000);
spr_register(env, SPR_IBAT1L, "IBAT1L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatl,
0x00000000);
spr_register(env, SPR_IBAT2U, "IBAT2U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatu,
0x00000000);
spr_register(env, SPR_IBAT2L, "IBAT2L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatl,
0x00000000);
spr_register(env, SPR_IBAT3U, "IBAT3U",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatu,
0x00000000);
spr_register(env, SPR_IBAT3L, "IBAT3L",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_601_ubat, &spr_write_601_ubatl,
0x00000000);
env->nb_BATs = 4;
#endif
}
static void gen_spr_74xx (CPUPPCState *env)
{
/* Processor identification */
spr_register(env, SPR_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_pir,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_74XX_MMCR2, "MMCR2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_74XX_UMMCR2, "UMMCR2",
&spr_read_ureg, SPR_NOACCESS,
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* XXX: not implemented */
spr_register(env, SPR_BAMR, "BAMR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_MSSCR0, "MSSCR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_HID1, "HID1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Altivec */
spr_register(env, SPR_VRSAVE, "VRSAVE",
&spr_read_generic, &spr_write_generic,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Not strictly an SPR */
vscr_init(env, 0x00010000);
}
static void gen_l3_ctrl (CPUPPCState *env)
{
/* L3CR */
/* XXX : not implemented */
spr_register(env, SPR_L3CR, "L3CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* L3ITCR0 */
/* XXX : not implemented */
spr_register(env, SPR_L3ITCR0, "L3ITCR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* L3PM */
/* XXX : not implemented */
spr_register(env, SPR_L3PM, "L3PM",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
{
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = nb_tlbs;
env->nb_ways = nb_ways;
env->id_tlbs = 1;
env->tlb_type = TLB_6XX;
/* XXX : not implemented */
spr_register(env, SPR_PTEHI, "PTEHI",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_PTELO, "PTELO",