提交 79aceca5 编写于 作者: B bellard

PowerPC support (Jocelyn Mayer)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@472 c046a42c-6fe2-441c-8c8c-71466251a162
上级 6a8c397d
/*
* PPC emulation for qemu: syscall definitions.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* XXX: ABSOLUTELY BUGGY:
* for now, this is quite just a cut-and-paste from i386 target...
*/
/* default linux values for the selectors */
#define __USER_DS (1)
struct target_pt_regs {
unsigned long gpr[32];
unsigned long nip;
unsigned long msr;
unsigned long orig_gpr3; /* Used for restarting system calls */
unsigned long ctr;
unsigned long link;
unsigned long xer;
unsigned long ccr;
unsigned long mq; /* 601 only (not used at present) */
/* Used on APUS to hold IPL value. */
unsigned long trap; /* Reason for being here */
unsigned long dar; /* Fault registers */
unsigned long dsisr;
unsigned long result; /* Result of a system call */
};
/* ioctls */
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
/*
* flags masks
*/
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct target_ipc_perm {
int key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct target_msqid_ds {
struct target_ipc_perm msg_perm;
unsigned int msg_first; /* really struct target_msg* */
unsigned int msg_last; /* really struct target_msg* */
unsigned int msg_stime; /* really target_time_t */
unsigned int msg_rtime; /* really target_time_t */
unsigned int msg_ctime; /* really target_time_t */
unsigned int wwait; /* really struct wait_queue* */
unsigned int rwait; /* really struct wait_queue* */
unsigned short msg_cbytes;
unsigned short msg_qnum;
unsigned short msg_qbytes;
unsigned short msg_lspid;
unsigned short msg_lrpid;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
int shm_segsz;
unsigned int shm_atime; /* really target_time_t */
unsigned int shm_dtime; /* really target_time_t */
unsigned int shm_ctime; /* really target_time_t */
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
void *attaches; /* really struct shm_desc * */
};
#define TARGET_IPC_RMID 0
#define TARGET_IPC_SET 1
#define TARGET_IPC_STAT 2
union target_semun {
int val;
unsigned int buf; /* really struct semid_ds * */
unsigned int array; /* really unsigned short * */
unsigned int __buf; /* really struct seminfo * */
unsigned int __pad; /* really void* */
};
/*
* This file contains the system call numbers.
*/
#define TARGET_NR_restart_syscall 0
#define TARGET_NR_exit 1
#define TARGET_NR_fork 2
#define TARGET_NR_read 3
#define TARGET_NR_write 4
#define TARGET_NR_open 5
#define TARGET_NR_close 6
#define TARGET_NR_waitpid 7
#define TARGET_NR_creat 8
#define TARGET_NR_link 9
#define TARGET_NR_unlink 10
#define TARGET_NR_execve 11
#define TARGET_NR_chdir 12
#define TARGET_NR_time 13
#define TARGET_NR_mknod 14
#define TARGET_NR_chmod 15
#define TARGET_NR_lchown32 16
#define TARGET_NR_break 17
#define TARGET_NR_oldstat 18
#define TARGET_NR_lseek 19
#define TARGET_NR_getpid 20
#define TARGET_NR_mount 21
#define TARGET_NR_umount 22
#define TARGET_NR_setuid32 23
#define TARGET_NR_getuid32 24
#define TARGET_NR_stime 25
#define TARGET_NR_ptrace 26
#define TARGET_NR_alarm 27
#define TARGET_NR_oldfstat 28
#define TARGET_NR_pause 29
#define TARGET_NR_utime 30
#define TARGET_NR_stty 31
#define TARGET_NR_gtty 32
#define TARGET_NR_access 33
#define TARGET_NR_nice 34
#define TARGET_NR_ftime 35
#define TARGET_NR_sync 36
#define TARGET_NR_kill 37
#define TARGET_NR_rename 38
#define TARGET_NR_mkdir 39
#define TARGET_NR_rmdir 40
#define TARGET_NR_dup 41
#define TARGET_NR_pipe 42
#define TARGET_NR_times 43
#define TARGET_NR_prof 44
#define TARGET_NR_brk 45
#define TARGET_NR_setgid32 46
#define TARGET_NR_getgid32 47
#define TARGET_NR_signal 48
#define TARGET_NR_geteuid32 49
#define TARGET_NR_getegid32 50
#define TARGET_NR_acct 51
#define TARGET_NR_umount2 52
#define TARGET_NR_lock 53
#define TARGET_NR_ioctl 54
#define TARGET_NR_fcntl 55
#define TARGET_NR_mpx 56
#define TARGET_NR_setpgid 57
#define TARGET_NR_ulimit 58
#define TARGET_NR_oldolduname 59
#define TARGET_NR_umask 60
#define TARGET_NR_chroot 61
#define TARGET_NR_ustat 62
#define TARGET_NR_dup2 63
#define TARGET_NR_getppid 64
#define TARGET_NR_getpgrp 65
#define TARGET_NR_setsid 66
#define TARGET_NR_sigaction 67
#define TARGET_NR_sgetmask 68
#define TARGET_NR_ssetmask 69
#define TARGET_NR_setreuid32 70
#define TARGET_NR_setregid32 71
#define TARGET_NR_sigsuspend 72
#define TARGET_NR_sigpending 73
#define TARGET_NR_sethostname 74
#define TARGET_NR_setrlimit 75
#define TARGET_NR_getrlimit 76
#define TARGET_NR_getrusage 77
#define TARGET_NR_gettimeofday 78
#define TARGET_NR_settimeofday 79
#define TARGET_NR_getgroups32 80
#define TARGET_NR_setgroups32 81
#define TARGET_NR_select 82
#define TARGET_NR_symlink 83
#define TARGET_NR_oldlstat 84
#define TARGET_NR_readlink 85
#define TARGET_NR_uselib 86
#define TARGET_NR_swapon 87
#define TARGET_NR_reboot 88
#define TARGET_NR_readdir 89
#define TARGET_NR_mmap 90
#define TARGET_NR_munmap 91
#define TARGET_NR_truncate 92
#define TARGET_NR_ftruncate 93
#define TARGET_NR_fchmod 94
#define TARGET_NR_fchown32 95
#define TARGET_NR_getpriority 96
#define TARGET_NR_setpriority 97
#define TARGET_NR_profil 98
#define TARGET_NR_statfs 99
#define TARGET_NR_fstatfs 100
#define TARGET_NR_ioperm 101
#define TARGET_NR_socketcall 102
#define TARGET_NR_syslog 103
#define TARGET_NR_setitimer 104
#define TARGET_NR_getitimer 105
#define TARGET_NR_stat 106
#define TARGET_NR_lstat 107
#define TARGET_NR_fstat 108
#define TARGET_NR_olduname 109
#define TARGET_NR_iopl 110
#define TARGET_NR_vhangup 111
#define TARGET_NR_idle 112
#define TARGET_NR_vm86 113
#define TARGET_NR_wait4 114
#define TARGET_NR_swapoff 115
#define TARGET_NR_sysinfo 116
#define TARGET_NR_ipc 117
#define TARGET_NR_fsync 118
#define TARGET_NR_sigreturn 119
#define TARGET_NR_clone 120
#define TARGET_NR_setdomainname 121
#define TARGET_NR_uname 122
#define TARGET_NR_modify_ldt 123
#define TARGET_NR_adjtimex 124
#define TARGET_NR_mprotect 125
#define TARGET_NR_sigprocmask 126
#define TARGET_NR_create_module 127
#define TARGET_NR_init_module 128
#define TARGET_NR_delete_module 129
#define TARGET_NR_get_kernel_syms 130
#define TARGET_NR_quotactl 131
#define TARGET_NR_getpgid 132
#define TARGET_NR_fchdir 133
#define TARGET_NR_bdflush 134
#define TARGET_NR_sysfs 135
#define TARGET_NR_personality 136
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid32 138
#define TARGET_NR_setfsgid32 139
#define TARGET_NR__llseek 140
#define TARGET_NR_getdents 141
#define TARGET_NR__newselect 142
#define TARGET_NR_flock 143
#define TARGET_NR_msync 144
#define TARGET_NR_readv 145
#define TARGET_NR_writev 146
#define TARGET_NR_getsid 147
#define TARGET_NR_fdatasync 148
#define TARGET_NR__sysctl 149
#define TARGET_NR_mlock 150
#define TARGET_NR_munlock 151
#define TARGET_NR_mlockall 152
#define TARGET_NR_munlockall 153
#define TARGET_NR_sched_setparam 154
#define TARGET_NR_sched_getparam 155
#define TARGET_NR_sched_setscheduler 156
#define TARGET_NR_sched_getscheduler 157
#define TARGET_NR_sched_yield 158
#define TARGET_NR_sched_get_priority_max 159
#define TARGET_NR_sched_get_priority_min 160
#define TARGET_NR_sched_rr_get_interval 161
#define TARGET_NR_nanosleep 162
#define TARGET_NR_mremap 163
#define TARGET_NR_setresuid32 164
#define TARGET_NR_getresuid32 165
#define TARGET_NR_query_module 166
#define TARGET_NR_poll 167
#define TARGET_NR_nfsservctl 168
#define TARGET_NR_setresgid32 169
#define TARGET_NR_getresgid32 170
#define TARGET_NR_prctl 171
#define TARGET_NR_rt_sigreturn 172
#define TARGET_NR_rt_sigaction 173
#define TARGET_NR_rt_sigprocmask 174
#define TARGET_NR_rt_sigpending 175
#define TARGET_NR_rt_sigtimedwait 176
#define TARGET_NR_rt_sigqueueinfo 177
#define TARGET_NR_rt_sigsuspend 178
#define TARGET_NR_pread64 179
#define TARGET_NR_pwrite64 180
#define TARGET_NR_chown32 181
#define TARGET_NR_getcwd 182
#define TARGET_NR_capget 183
#define TARGET_NR_capset 184
#define TARGET_NR_sigaltstack 185
#define TARGET_NR_sendfile 186
#define TARGET_NR_getpmsg 187 /* some people actually want streams */
#define TARGET_NR_putpmsg 188 /* some people actually want streams */
#define TARGET_NR_vfork 189
#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */
#define TARGET_NR_readahead 191
#define TARGET_NR_mmap2 192
#define TARGET_NR_truncate64 193
#define TARGET_NR_ftruncate64 194
#define TARGET_NR_stat64 195
#define TARGET_NR_lstat64 196
#define TARGET_NR_fstat64 197
#define TARGET_NR_pciconfig_read 198
#define TARGET_NR_pciconfig_write 199
#define TARGET_NR_pciconfig_iobase 200
#define TARGET_NR_multiplexer 201
#define TARGET_NR_getdents64 202
#define TARGET_NR_pivot_root 203
#define TARGET_NR_fcntl64 204
#define TARGET_NR_madvise 205
#define TARGET_NR_mincore 206
#define TARGET_NR_gettid 207
#define TARGET_NR_tkill 208
#define TARGET_NR_setxattr 209
#define TARGET_NR_lsetxattr 210
#define TARGET_NR_fsetxattr 211
#define TARGET_NR_getxattr 212
#define TARGET_NR_lgetxattr 213
#define TARGET_NR_fgetxattr 214
#define TARGET_NR_listxattr 215
#define TARGET_NR_llistxattr 216
#define TARGET_NR_flistxattr 217
#define TARGET_NR_removexattr 218
#define TARGET_NR_lremovexattr 219
#define TARGET_NR_fremovexattr 220
#define TARGET_NR_futex 221
#define TARGET_NR_sched_setaffinity 222
#define TARGET_NR_sched_getaffinity 223
/* 224 currently unused */
#define TARGET_NR_tuxcall 225
#define TARGET_NR_sendfile64 226
#define TARGET_NR_io_setup 227
#define TARGET_NR_io_destroy 228
#define TARGET_NR_io_getevents 229
#define TARGET_NR_io_submit 230
#define TARGET_NR_io_cancel 231
#define TARGET_NR_set_tid_address 232
#define TARGET_NR_fadvise64 233
#define TARGET_NR_exit_group 234
#define TARGET_NR_lookup_dcookie 235
#define TARGET_NR_epoll_create 236
#define TARGET_NR_epoll_ctl 237
#define TARGET_NR_epoll_wait 238
#define TARGET_NR_remap_file_pages 239
#define TARGET_NR_timer_create 240
#define TARGET_NR_timer_settime 241
#define TARGET_NR_timer_gettime 242
#define TARGET_NR_timer_getoverrun 243
#define TARGET_NR_timer_delete 244
#define TARGET_NR_clock_settime 245
#define TARGET_NR_clock_gettime 246
#define TARGET_NR_clock_getres 247
#define TARGET_NR_clock_nanosleep 248
#define TARGET_NR_swapcontext 249
#define TARGET_NR_tgkill 250
#define TARGET_NR_utimes 251
#define TARGET_NR_statfs64 252
#define TARGET_NR_fstatfs64 253
#define TARGET_NR_fadvise64_64 254
/*
* PPC emulation cpu definitions for qemu.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined (__CPU_PPC_H__)
#define __CPU_PPC_H__
#include <endian.h>
#include <asm/byteorder.h>
#include "cpu-defs.h"
/*** Sign extend constants ***/
/* 8 to 32 bits */
static inline int32_t s_ext8 (uint8_t value)
{
int8_t *tmp = &value;
return *tmp;
}
/* 16 to 32 bits */
static inline int32_t s_ext16 (uint16_t value)
{
int16_t *tmp = &value;
return *tmp;
}
/* 24 to 32 bits */
static inline int32_t s_ext24 (uint32_t value)
{
uint16_t utmp = (value >> 8) & 0xFFFF;
int16_t *tmp = &utmp;
return (*tmp << 8) | (value & 0xFF);
}
#include "config.h"
#include <setjmp.h>
/* Floting point status and control register */
#define FPSCR_FX 31
#define FPSCR_FEX 30
#define FPSCR_VX 29
#define FPSCR_OX 28
#define FPSCR_UX 27
#define FPSCR_ZX 26
#define FPSCR_XX 25
#define FPSCR_VXSNAN 24
#define FPSCR_VXISI 26
#define FPSCR_VXIDI 25
#define FPSCR_VXZDZ 21
#define FPSCR_VXIMZ 20
#define FPSCR_VXVC 18
#define FPSCR_FR 17
#define FPSCR_FI 16
#define FPSCR_FPRF 11
#define FPSCR_VXSOFT 9
#define FPSCR_VXSQRT 8
#define FPSCR_VXCVI 7
#define FPSCR_OE 6
#define FPSCR_UE 5
#define FPSCR_ZE 4
#define FPSCR_XE 3
#define FPSCR_NI 2
#define FPSCR_RN 0
#define fpscr_fx env->fpscr[FPSCR_FX]
#define fpscr_fex env->fpscr[FPSCR_FEX]
#define fpscr_vx env->fpscr[FPSCR_VX]
#define fpscr_ox env->fpscr[FPSCR_OX]
#define fpscr_ux env->fpscr[FPSCR_UX]
#define fpscr_zx env->fpscr[FPSCR_ZX]
#define fpscr_xx env->fpscr[FPSCR_XX]
#define fpscr_vsxnan env->fpscr[FPSCR_VXSNAN]
#define fpscr_vxisi env->fpscr[FPSCR_VXISI]
#define fpscr_vxidi env->fpscr[FPSCR_VXIDI]
#define fpscr_vxzdz env->fpscr[FPSCR_VXZDZ]
#define fpscr_vximz env->fpscr[FPSCR_VXIMZ]
#define fpscr_fr env->fpscr[FPSCR_FR]
#define fpscr_fi env->fpscr[FPSCR_FI]
#define fpscr_fprf env->fpscr[FPSCR_FPRF]
#define fpscr_vxsoft env->fpscr[FPSCR_VXSOFT]
#define fpscr_vxsqrt env->fpscr[FPSCR_VXSQRT]
#define fpscr_oe env->fpscr[FPSCR_OE]
#define fpscr_ue env->fpscr[FPSCR_UE]
#define fpscr_ze env->fpscr[FPSCR_ZE]
#define fpscr_xe env->fpscr[FPSCR_XE]
#define fpscr_ni env->fpscr[FPSCR_NI]
#define fpscr_rn env->fpscr[FPSCR_RN]
/* Supervisor mode registers */
/* Machine state register */
#define MSR_POW 18
#define MSR_ILE 16
#define MSR_EE 15
#define MSR_PR 14
#define MSR_FP 13
#define MSR_ME 12
#define MSR_FE0 11
#define MSR_SE 10
#define MSR_BE 9
#define MSR_FE1 8
#define MSR_IP 6
#define MSR_IR 5
#define MSR_DR 4
#define MSR_RI 1
#define MSR_LE 0
#define msr_pow env->msr[MSR_POW]
#define msr_ile env->msr[MSR_ILE]
#define msr_ee env->msr[MSR_EE]
#define msr_pr env->msr[MSR_PR]
#define msr_fp env->msr[MSR_FP]
#define msr_me env->msr[MSR_ME]
#define msr_fe0 env->msr[MSR_FE0]
#define msr_se env->msr[MSR_SE]
#define msr_be env->msr[MSR_BE]
#define msr_fe1 env->msr[MSR_FE1]
#define msr_ip env->msr[MSR_IP]
#define msr_ir env->msr[MSR_IR]
#define msr_dr env->msr[MSR_DR]
#define msr_ri env->msr[MSR_RI]
#define msr_le env->msr[MSR_LE]
/* Segment registers */
typedef struct ppc_sr_t {
uint32_t t:1;
uint32_t ks:1;
uint32_t kp:1;
uint32_t n:1;
uint32_t res:4;
uint32_t vsid:24;
} ppc_sr_t;
typedef struct CPUPPCState {
/* general purpose registers */
uint32_t gpr[32];
/* floating point registers */
uint64_t fpr[32];
/* segment registers */
ppc_sr_t sr[16];
/* special purpose registers */
uint32_t spr[1024];
/* XER */
uint8_t xer[32];
/* Reservation address */
uint32_t reserve;
/* machine state register */
uint8_t msr[32];
/* condition register */
uint8_t crf[8];
/* floating point status and control register */
uint8_t fpscr[32];
uint32_t nip;
/* CPU exception code */
uint32_t exception;
/* qemu dedicated */
int interrupt_request;
jmp_buf jmp_env;
int exception_index;
int error_code;
int user_mode_only; /* user mode only simulation */
struct TranslationBlock *current_tb; /* currently executing TB */
/* user data */
void *opaque;
} CPUPPCState;
CPUPPCState *cpu_ppc_init(void);
int cpu_ppc_exec(CPUPPCState *s);
void cpu_ppc_close(CPUPPCState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
struct siginfo;
int cpu_ppc_signal_handler(int host_signum, struct siginfo *info,
void *puc);
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
#define ugpr(n) (env->gpr[n])
#define fpr(n) (env->fpr[n])
#define SPR_ENCODE(sprn) \
(((sprn) >> 5) | (((sprn) & 0x1F) << 5))
/* User mode SPR */
#define spr(n) env->spr[n]
//#define XER spr[1]
#define XER env->xer
#define XER_SO 31
#define XER_OV 30
#define XER_CA 29
#define XER_BC 0
#define xer_so env->xer[XER_SO]
#define xer_ov env->xer[XER_OV]
#define xer_ca env->xer[XER_CA]
#define xer_bc env->xer[XER_BC]
#define LR spr[SPR_ENCODE(8)]
#define CTR spr[SPR_ENCODE(9)]
/* VEA mode SPR */
#define V_TBL spr[SPR_ENCODE(268)]
#define V_TBU spr[SPR_ENCODE(269)]
/* supervisor mode SPR */
#define DSISR spr[SPR_ENCODE(18)]
#define DAR spr[SPR_ENCODE(19)]
#define DEC spr[SPR_ENCODE(22)]
#define SDR1 spr[SPR_ENCODE(25)]
typedef struct ppc_sdr1_t {
uint32_t htaborg:16;
uint32_t res:7;
uint32_t htabmask:9;
} ppc_sdr1_t;
#define SRR0 spr[SPR_ENCODE(26)]
#define SRR0_MASK 0xFFFFFFFC
#define SRR1 spr[SPR_ENCODE(27)]
#define SPRG0 spr[SPR_ENCODE(272)]
#define SPRG1 spr[SPR_ENCODE(273)]
#define SPRG2 spr[SPR_ENCODE(274)]
#define SPRG3 spr[SPR_ENCODE(275)]
#define EAR spr[SPR_ENCODE(282)]
typedef struct ppc_ear_t {
uint32_t e:1;
uint32_t res:25;
uint32_t rid:6;
} ppc_ear_t;
#define TBL spr[SPR_ENCODE(284)]
#define TBU spr[SPR_ENCODE(285)]
#define PVR spr[SPR_ENCODE(287)]
typedef struct ppc_pvr_t {
uint32_t version:16;
uint32_t revision:16;
} ppc_pvr_t;
#define IBAT0U spr[SPR_ENCODE(528)]
#define IBAT0L spr[SPR_ENCODE(529)]
#define IBAT1U spr[SPR_ENCODE(530)]
#define IBAT1L spr[SPR_ENCODE(531)]
#define IBAT2U spr[SPR_ENCODE(532)]
#define IBAT2L spr[SPR_ENCODE(533)]
#define IBAT3U spr[SPR_ENCODE(534)]
#define IBAT3L spr[SPR_ENCODE(535)]
#define DBAT0U spr[SPR_ENCODE(536)]
#define DBAT0L spr[SPR_ENCODE(537)]
#define DBAT1U spr[SPR_ENCODE(538)]
#define DBAT1L spr[SPR_ENCODE(539)]
#define DBAT2U spr[SPR_ENCODE(540)]
#define DBAT2L spr[SPR_ENCODE(541)]
#define DBAT3U spr[SPR_ENCODE(542)]
#define DBAT3L spr[SPR_ENCODE(543)]
typedef struct ppc_ubat_t {
uint32_t bepi:15;
uint32_t res:4;
uint32_t bl:11;
uint32_t vs:1;
uint32_t vp:1;
} ppc_ubat_t;
typedef struct ppc_lbat_t {
uint32_t brpn:15;
uint32_t res0:10;
uint32_t w:1;
uint32_t i:1;
uint32_t m:1;
uint32_t g:1;
uint32_t res1:1;
uint32_t pp:2;
} ppc_lbat_t;
#define DABR spr[SPR_ENCODE(1013)]
#define DABR_MASK 0xFFFFFFF8
typedef struct ppc_dabr_t {
uint32_t dab:29;
uint32_t bt:1;
uint32_t dw:1;
uint32_t dr:1;
} ppc_dabr_t;
#define FPECR spr[SPR_ENCODE(1022)]
#define PIR spr[SPR_ENCODE(1023)]
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
CPUPPCState *cpu_ppc_init(void);
int cpu_ppc_exec(CPUPPCState *s);
void cpu_ppc_close(CPUPPCState *s);
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
/* Exeptions */
enum {
EXCP_NONE = 0x00,
/* PPC hardware exceptions : exception vector / 0x100 */
EXCP_RESET = 0x01, /* System reset */
EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */
EXCP_DSI = 0x03, /* Impossible memory access */
EXCP_ISI = 0x04, /* Impossible instruction fetch */
EXCP_EXTERNAL = 0x05, /* External interruption */
EXCP_ALIGN = 0x06, /* Alignment exception */
EXCP_PROGRAM = 0x07, /* Program exception */
EXCP_NO_FP = 0x08, /* No floating point */
EXCP_DECR = 0x09, /* Decrementer exception */
EXCP_RESA = 0x0A, /* Implementation specific */
EXCP_RESB = 0x0B, /* Implementation specific */
EXCP_SYSCALL = 0x0C, /* System call */
EXCP_TRACE = 0x0D, /* Trace exception (optional) */
EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */
#if 0
/* Exeption subtypes for EXCP_DSI */
EXCP_DSI_TRANSLATE = 0x10301, /* Data address can't be translated */
EXCP_DSI_NOTSUP = 0x10302, /* Access type not supported */
EXCP_DSI_PROT = 0x10303, /* Memory protection violation */
EXCP_DSI_EXTERNAL = 0x10304, /* External access disabled */
EXCP_DSI_DABR = 0x10305, /* Data address breakpoint */
/* Exeption subtypes for EXCP_ISI */
EXCP_ISI_TRANSLATE = 0x10401, /* Code address can't be translated */
EXCP_ISI_NOTSUP = 0x10402, /* Access type not supported */
EXCP_ISI_PROT = 0x10403, /* Memory protection violation */
EXCP_ISI_GUARD = 0x10404, /* Fetch into guarded memory */
/* Exeption subtypes for EXCP_ALIGN */
EXCP_ALIGN_FP = 0x10601, /* FP alignment exception */
EXCP_ALIGN_LST = 0x10602, /* Unaligned memory load/store */
EXCP_ALIGN_LE = 0x10603, /* Unaligned little-endian access */
EXCP_ALIGN_PROT = 0x10604, /* Access cross protection boundary */
EXCP_ALIGN_BAT = 0x10605, /* Access cross a BAT/seg boundary */
EXCP_ALIGN_CACHE = 0x10606, /* Impossible dcbz access */
/* Exeption subtypes for EXCP_PROGRAM */
/* FP exceptions */
EXCP_FP_OX = 0x10701, /* FP overflow */
EXCP_FP_UX = 0x10702, /* FP underflow */
EXCP_FP_ZX = 0x10703, /* FP divide by zero */
EXCP_FP_XX = 0x10704, /* FP inexact */
EXCP_FP_VXNAN = 0x10705, /* FP invalid SNaN op */
EXCP_FP_VXISI = 0x10706, /* FP invalid infinite substraction */
EXCP_FP_VXIDI = 0x10707, /* FP invalid infinite divide */
EXCP_FP_VXZDZ = 0x10708, /* FP invalid zero divide */
EXCP_FP_VXIMZ = 0x10709, /* FP invalid infinite * zero */
EXCP_FP_VXVC = 0x1070A, /* FP invalid compare */
EXCP_FP_VXSOFT = 0x1070B, /* FP invalid operation */
EXCP_FP_VXSQRT = 0x1070C, /* FP invalid square root */
EXCP_FP_VXCVI = 0x1070D, /* FP invalid integer conversion */
/* Invalid instruction */
EXCP_INVAL_INVAL = 0x10711, /* Invalid instruction */
EXCP_INVAL_LSWX = 0x10712, /* Invalid lswx instruction */
EXCP_INVAL_SPR = 0x10713, /* Invalid SPR access */
EXCP_INVAL_FP = 0x10714, /* Unimplemented mandatory fp instr */
#endif
EXCP_INVAL = 0x70, /* Invalid instruction */
/* Privileged instruction */
EXCP_PRIV = 0x71, /* Privileged instruction */
/* Trap */
EXCP_TRAP = 0x72, /* Trap */
/* Special cases where we want to stop translation */
EXCP_MTMSR = 0x103, /* mtmsr instruction: */
/* may change privilege level */
EXCP_BRANCH = 0x104, /* branch instruction */
};
/*
* We need to put in some extra aux table entries to tell glibc what
* the cache block size is, so it can use the dcbz instruction safely.
*/
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
/* A special ignored type value for PPC, for glibc compatibility. */
#define AT_IGNOREPPC 22
/*
* The requirements here are:
* - keep the final alignment of sp (sp & 0xf)
* - make sure the 32-bit value at the first 16 byte aligned position of
* AUXV is greater than 16 for glibc compatibility.
* AT_IGNOREPPC is used for that.
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
*/
#define DLINFO_ARCH_ITEMS 3
#define ARCH_DLINFO \
do { \
/* \
* Now handle glibc compatibility. \
*/ \
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
\
NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \
NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \
NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
} while (0)
#endif /* !defined (__CPU_PPC_H__) */
/*
* PPC emulation definitions for qemu.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined (__PPC_H__)
#define __PPC_H__
#include "dyngen-exec.h"
register struct CPUPPCState *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#define PARAM(n) ((uint32_t)PARAM##n)
#define SPARAM(n) ((int32_t)PARAM##n)
#define RETURN() __asm__ __volatile__("");
#include "cpu.h"
#include "exec-all.h"
static inline uint8_t ld8 (uint32_t EA)
{
return *((uint8_t *)EA);
}
static inline uint16_t ld16 (uint32_t EA)
{
return __be16_to_cpu(*((uint16_t *)EA));
}
static inline uint16_t ld16r (uint32_t EA)
{
return __le16_to_cpu(*((uint16_t *)EA));
}
static inline uint32_t ld32 (uint32_t EA)
{
return __be32_to_cpu(*((uint32_t *)EA));
}
static inline uint32_t ld32r (uint32_t EA)
{
return __le32_to_cpu(*((uint32_t *)EA));
}
static inline uint64_t ld64 (uint32_t EA)
{
return __be64_to_cpu(*((uint64_t *)EA));
}
static inline uint64_t ld64r (uint32_t EA)
{
return __le64_to_cpu(*((uint64_t *)EA));
}
static inline void st8 (uint32_t EA, uint8_t data)
{
*((uint8_t *)EA) = data;
}
static inline void st16 (uint32_t EA, uint16_t data)
{
*((uint16_t *)EA) = __cpu_to_be16(data);
}
static inline void st16r (uint32_t EA, uint16_t data)
{
*((uint16_t *)EA) = __cpu_to_le16(data);
}
static inline void st32 (uint32_t EA, uint32_t data)
{
*((uint32_t *)EA) = __cpu_to_be32(data);
}
static inline void st32r (uint32_t EA, uint32_t data)
{
*((uint32_t *)EA) = __cpu_to_le32(data);
}
static inline void st64 (uint32_t EA, uint64_t data)
{
*((uint64_t *)EA) = __cpu_to_be64(data);
}
static inline void st64r (uint32_t EA, uint64_t data)
{
*((uint64_t *)EA) = __cpu_to_le64(data);
}
static inline void set_CRn(int n, uint8_t value)
{
env->crf[n] = value;
}
static inline void set_carry (void)
{
xer_ca = 1;
}
static inline void reset_carry (void)
{
xer_ca = 0;
}
static inline void set_overflow (void)
{
xer_so = 1;
xer_ov = 1;
}
static inline void reset_overflow (void)
{
xer_ov = 0;
}
static inline uint32_t rotl (uint32_t i, int n)
{
return ((i << n) | (i >> (32 - n)));
}
void raise_exception (int exception_index);
void raise_exception_err (int exception_index, int error_code);
uint32_t do_load_cr (void);
void do_store_cr (uint32_t crn, uint32_t value);
uint32_t do_load_xer (void);
void do_store_xer (uint32_t value);
uint32_t do_load_msr (void);
void do_store_msr (uint32_t msr_value);
uint32_t do_load_fpscr (void);
void do_store_fpscr (uint8_t mask, uint32_t fp);
int32_t do_sraw(int32_t Ta, uint32_t Tb);
void do_lmw (int reg, uint32_t src);
void do_stmw (int reg, uint32_t dest);
void do_lsw (uint32_t reg, int count, uint32_t src);
void do_stsw (uint32_t reg, int count, uint32_t dest);
#endif /* !defined (__PPC_H__) */
/*
* PPC emulation helpers for qemu.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec.h"
extern FILE *logfile;
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
/* shortcuts to generate exceptions */
void raise_exception_err (int exception_index, int error_code)
{
env->exception_index = exception_index;
env->error_code = error_code;
cpu_loop_exit();
}
void raise_exception (int exception_index)
{
env->exception_index = exception_index;
env->error_code = 0;
cpu_loop_exit();
}
/* Helpers for "fat" micro operations */
uint32_t do_load_cr (void)
{
return (env->crf[0] << 28) |
(env->crf[1] << 24) |
(env->crf[2] << 20) |
(env->crf[3] << 16) |
(env->crf[4] << 12) |
(env->crf[5] << 8) |
(env->crf[6] << 4) |
(env->crf[7] << 0);
}
void do_store_cr (uint32_t crn, uint32_t value)
{
int i, sh;
for (i = 0, sh = 7; i < 8; i++, sh --) {
if (crn & (1 << sh))
env->crf[i] = (value >> (sh * 4)) & 0xF;
}
}
uint32_t do_load_xer (void)
{
return (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_ca << XER_CA) |
(xer_bc << XER_BC);
}
void do_store_xer (uint32_t value)
{
xer_so = (value >> XER_SO) & 0x01;
xer_ov = (value >> XER_OV) & 0x01;
xer_ca = (value >> XER_CA) & 0x01;
xer_bc = (value >> XER_BC) & 0x1f;
}
uint32_t do_load_msr (void)
{
return (msr_pow << MSR_POW) |
(msr_ile << MSR_ILE) |
(msr_ee << MSR_EE) |
(msr_pr << MSR_PR) |
(msr_fp << MSR_FP) |
(msr_me << MSR_ME) |
(msr_fe0 << MSR_FE0) |
(msr_se << MSR_SE) |
(msr_be << MSR_BE) |
(msr_fe1 << MSR_FE1) |
(msr_ip << MSR_IP) |
(msr_ir << MSR_IR) |
(msr_dr << MSR_DR) |
(msr_ri << MSR_RI) |
(msr_le << MSR_LE);
}
void do_store_msr (uint32_t msr_value)
{
msr_pow = (msr_value >> MSR_POW) & 0x03;
msr_ile = (msr_value >> MSR_ILE) & 0x01;
msr_ee = (msr_value >> MSR_EE) & 0x01;
msr_pr = (msr_value >> MSR_PR) & 0x01;
msr_fp = (msr_value >> MSR_FP) & 0x01;
msr_me = (msr_value >> MSR_ME) & 0x01;
msr_fe0 = (msr_value >> MSR_FE0) & 0x01;
msr_se = (msr_value >> MSR_SE) & 0x01;
msr_be = (msr_value >> MSR_BE) & 0x01;
msr_fe1 = (msr_value >> MSR_FE1) & 0x01;
msr_ip = (msr_value >> MSR_IP) & 0x01;
msr_ir = (msr_value >> MSR_IR) & 0x01;
msr_dr = (msr_value >> MSR_DR) & 0x01;
msr_ri = (msr_value >> MSR_RI) & 0x01;
msr_le = (msr_value >> MSR_LE) & 0x01;
}
/* The 32 MSB of the target fpr are undefined. They'll be zero... */
uint32_t do_load_fpscr (void)
{
return (fpscr_fx << FPSCR_FX) |
(fpscr_fex << FPSCR_FEX) |
(fpscr_vx << FPSCR_VX) |
(fpscr_ox << FPSCR_OX) |
(fpscr_ux << FPSCR_UX) |
(fpscr_zx << FPSCR_ZX) |
(fpscr_xx << FPSCR_XX) |
(fpscr_vsxnan << FPSCR_VXSNAN) |
(fpscr_vxisi << FPSCR_VXISI) |
(fpscr_vxidi << FPSCR_VXIDI) |
(fpscr_vxzdz << FPSCR_VXZDZ) |
(fpscr_vximz << FPSCR_VXIMZ) |
(fpscr_fr << FPSCR_FR) |
(fpscr_fi << FPSCR_FI) |
(fpscr_fprf << FPSCR_FPRF) |
(fpscr_vxsoft << FPSCR_VXSOFT) |
(fpscr_vxsqrt << FPSCR_VXSQRT) |
(fpscr_oe << FPSCR_OE) |
(fpscr_ue << FPSCR_UE) |
(fpscr_ze << FPSCR_ZE) |
(fpscr_xe << FPSCR_XE) |
(fpscr_ni << FPSCR_NI) |
(fpscr_rn << FPSCR_RN);
}
/* We keep only 32 bits of input... */
/* For now, this is COMPLETELY BUGGY ! */
void do_store_fpscr (uint8_t mask, uint32_t fp)
{
int i;
for (i = 0; i < 7; i++) {
if ((mask & (1 << i)) == 0)
fp &= ~(0xf << (4 * i));
}
if ((mask & 80) != 0)
fpscr_fx = (fp >> FPSCR_FX) & 0x01;
fpscr_fex = (fp >> FPSCR_FEX) & 0x01;
fpscr_vx = (fp >> FPSCR_VX) & 0x01;
fpscr_ox = (fp >> FPSCR_OX) & 0x01;
fpscr_ux = (fp >> FPSCR_UX) & 0x01;
fpscr_zx = (fp >> FPSCR_ZX) & 0x01;
fpscr_xx = (fp >> FPSCR_XX) & 0x01;
fpscr_vsxnan = (fp >> FPSCR_VXSNAN) & 0x01;
fpscr_vxisi = (fp >> FPSCR_VXISI) & 0x01;
fpscr_vxidi = (fp >> FPSCR_VXIDI) & 0x01;
fpscr_vxzdz = (fp >> FPSCR_VXZDZ) & 0x01;
fpscr_vximz = (fp >> FPSCR_VXIMZ) & 0x01;
fpscr_fr = (fp >> FPSCR_FR) & 0x01;
fpscr_fi = (fp >> FPSCR_FI) & 0x01;
fpscr_fprf = (fp >> FPSCR_FPRF) & 0x1F;
fpscr_vxsoft = (fp >> FPSCR_VXSOFT) & 0x01;
fpscr_vxsqrt = (fp >> FPSCR_VXSQRT) & 0x01;
fpscr_oe = (fp >> FPSCR_OE) & 0x01;
fpscr_ue = (fp >> FPSCR_UE) & 0x01;
fpscr_ze = (fp >> FPSCR_ZE) & 0x01;
fpscr_xe = (fp >> FPSCR_XE) & 0x01;
fpscr_ni = (fp >> FPSCR_NI) & 0x01;
fpscr_rn = (fp >> FPSCR_RN) & 0x03;
}
int32_t do_sraw(int32_t value, uint32_t shift)
{
int32_t ret;
xer_ca = 0;
if (shift & 0x20) {
ret = (-1) * ((uint32_t)value >> 31);
if (ret < 0)
xer_ca = 1;
} else {
ret = value >> (shift & 0x1f);
if (ret < 0 && (value & ((1 << shift) - 1)) != 0)
xer_ca = 1;
}
return ret;
}
void do_lmw (int reg, uint32_t src)
{
for (; reg <= 31; reg++, src += 4)
ugpr(reg) = ld32(src);
}
void do_stmw (int reg, uint32_t dest)
{
for (; reg <= 31; reg++, dest += 4)
st32(dest, ugpr(reg));
}
void do_lsw (uint32_t reg, int count, uint32_t src)
{
uint32_t tmp;
int sh;
for (; count > 3; count -= 4, src += 4) {
if (reg == 32)
reg = 0;
ugpr(reg++) = ld32(src);
}
if (count > 0) {
for (sh = 24, tmp = 0; count > 0; count--, src++, sh -= 8) {
if (reg == 32)
reg = 0;
tmp |= ld8(src) << sh;
if (sh == 0) {
sh = 32;
ugpr(reg++) = tmp;
tmp = 0;
}
}
ugpr(reg) = tmp;
}
}
void do_stsw (uint32_t reg, int count, uint32_t dest)
{
int sh;
for (; count > 3; count -= 4, dest += 4) {
if (reg == 32)
reg = 0;
st32(dest, ugpr(reg++));
}
if (count > 0) {
for (sh = 24; count > 0; count--, dest++, sh -= 8) {
if (reg == 32)
reg = 0;
st8(dest, (ugpr(reg) >> sh) & 0xFF);
if (sh == 0) {
sh = 32;
reg++;
}
}
}
}
/*
* PPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "exec.h"
#define regs (env)
extern uint32_t __a;
extern uint32_t __b;
extern uint32_t __c;
extern uint32_t __d;
extern uint32_t __e;
extern uint32_t __f;
#define Ts0 (int32_t)T0
#define Ts1 (int32_t)T1
#define Ts2 (int32_t)T2
#include "op-multi.c"
#define PPC_OP(name) void op_##name(void)
/* PPC state maintenance operations */
/* set_Rc0 */
PPC_OP(set_Rc0)
{
uint32_t tmp;
if (Ts0 < 0) {
tmp = 0x08;
} else if (Ts0 > 0) {
tmp = 0x04;
} else {
tmp = 0x02;
}
set_CRn(0, tmp);
RETURN();
}
PPC_OP(set_Rc0_ov)
{
uint32_t tmp;
if (Ts0 < 0) {
tmp = 0x08;
} else if (Ts0 > 0) {
tmp = 0x04;
} else {
tmp = 0x02;
}
tmp |= xer_ov;
set_CRn(0, tmp);
RETURN();
}
/* reset_Rc0 */
PPC_OP(reset_Rc0)
{
set_CRn(0, 0x02 | xer_ov);
RETURN();
}
/* set_Rc0_1 */
PPC_OP(set_Rc0_1)
{
set_CRn(0, 0x04 | xer_ov);
RETURN();
}
PPC_OP(set_T0)
{
T0 = PARAM(1);
RETURN();
}
PPC_OP(set_T1)
{
T1 = PARAM(1);
RETURN();
}
PPC_OP(set_T2)
{
T2 = PARAM(1);
RETURN();
}
/* Update time base */
PPC_OP(update_tb)
{
T0 = regs->spr[SPR_ENCODE(268)];
T1 = T0;
T0 += PARAM(1);
if (T0 < T1) {
T1 = regs->spr[SPR_ENCODE(269)] + 1;
regs->spr[SPR_ENCODE(269)] = T1;
}
regs->spr[SPR_ENCODE(268)] = T0;
RETURN();
}
PPC_OP(raise_exception)
{
raise_exception(PARAM(1));
RETURN();
}
PPC_OP(exit_tb)
{
EXIT_TB();
}
PPC_OP(load_cr)
{
T0 = do_load_cr();
RETURN();
}
PPC_OP(store_cr)
{
do_store_cr(PARAM(1), T0);
RETURN();
}
PPC_OP(load_xer_cr)
{
T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
RETURN();
}
PPC_OP(clear_xer_cr)
{
xer_so = 0;
xer_ov = 0;
xer_ca = 0;
RETURN();
}
PPC_OP(load_xer_bc)
{
T0 = xer_bc;
RETURN();
}
PPC_OP(load_xer)
{
T0 = do_load_xer();
RETURN();
}
PPC_OP(store_xer)
{
do_store_xer(T0);
RETURN();
}
PPC_OP(load_msr)
{
T0 = do_load_msr();
RETURN();
}
PPC_OP(store_msr)
{
do_store_msr(T0);
RETURN();
}
PPC_OP(load_lr)
{
regs->LR = PARAM(1);
RETURN();
}
/* Set reservation */
PPC_OP(set_reservation)
{
regs->reserve = T1 & ~0x03;
RETURN();
}
/* Reset reservation */
PPC_OP(reset_reservation)
{
regs->reserve = 0;
RETURN();
}
/* crf operations */
PPC_OP(getbit_T0)
{
T0 = (T0 >> PARAM(1)) & 1;
RETURN();
}
PPC_OP(getbit_T1)
{
T1 = (T1 >> PARAM(1)) & 1;
RETURN();
}
PPC_OP(setcrfbit)
{
T1 = (T1 & PARAM(1)) | (T0 << PARAM(2));
RETURN();
}
/* Branch */
#define __PPC_OP_B(name, target) \
PPC_OP(name) \
{ \
regs->nip = (target); \
RETURN(); \
}
#define __PPC_OP_BL(name, target) \
PPC_OP(name) \
{ \
regs->LR = PARAM(1); \
regs->nip = (target); \
RETURN(); \
}
#define PPC_OP_B(name, target) \
__PPC_OP_B(name, target); \
__PPC_OP_BL(name##l, target)
#define __PPC_OP_BC(name, cond, target) \
PPC_OP(name) \
{ \
if (cond) { \
T0 = (target); \
} else { \
T0 = PARAM(1); \
} \
regs->nip = T0; \
RETURN(); \
}
#define __PPC_OP_BCL(name, cond, target) \
PPC_OP(name) \
{ \
if (cond) { \
T0 = (target); \
regs->LR = PARAM(1); \
} else { \
T0 = PARAM(1); \
} \
regs->nip = T0; \
RETURN(); \
}
#define _PPC_OP_BC(name, namel, cond, target) \
__PPC_OP_BC(name, cond, target); \
__PPC_OP_BCL(namel, cond, target)
/* Branch to target */
#define PPC_OP_BC(name, cond) \
_PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2))
PPC_OP_B(b, PARAM(1));
PPC_OP_BC(ctr, (regs->CTR != 0));
PPC_OP_BC(ctr_true, (regs->CTR != 0 && (T0 & PARAM(3)) != 0));
PPC_OP_BC(ctr_false, (regs->CTR != 0 && (T0 & PARAM(3)) == 0));
PPC_OP_BC(ctrz, (regs->CTR == 0));
PPC_OP_BC(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(3)) != 0));
PPC_OP_BC(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(3)) == 0));
PPC_OP_BC(true, ((T0 & PARAM(3)) != 0));
PPC_OP_BC(false, ((T0 & PARAM(3)) == 0));
/* Branch to CTR */
#define PPC_OP_BCCTR(name, cond) \
_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->CTR & ~0x03)
PPC_OP_B(bctr, regs->CTR & ~0x03);
PPC_OP_BCCTR(ctr, (regs->CTR != 0));
PPC_OP_BCCTR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
PPC_OP_BCCTR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
PPC_OP_BCCTR(ctrz, (regs->CTR == 0));
PPC_OP_BCCTR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
PPC_OP_BCCTR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
PPC_OP_BCCTR(true, ((T0 & PARAM(2)) != 0));
PPC_OP_BCCTR(false, ((T0 & PARAM(2)) == 0));
/* Branch to LR */
#define PPC_OP_BCLR(name, cond) \
_PPC_OP_BC(blr_##name, blrl_##name, cond, regs->LR & ~0x03)
PPC_OP_B(blr, regs->LR & ~0x03);
PPC_OP_BCLR(ctr, (regs->CTR != 0));
PPC_OP_BCLR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
PPC_OP_BCLR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
PPC_OP_BCLR(ctrz, (regs->CTR == 0));
PPC_OP_BCLR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
PPC_OP_BCLR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
PPC_OP_BCLR(true, ((T0 & PARAM(2)) != 0));
PPC_OP_BCLR(false, ((T0 & PARAM(2)) == 0));
/* CTR maintenance */
PPC_OP(dec_ctr)
{
regs->CTR--;
RETURN();
}
/*** Integer arithmetic ***/
/* add */
PPC_OP(add)
{
T0 += T1;
RETURN();
}
PPC_OP(addo)
{
T2 = T0;
T0 += T1;
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
RETURN();
}
/* add carrying */
PPC_OP(addc)
{
T2 = T0;
T0 += T1;
if (T0 < T2) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
PPC_OP(addco)
{
T2 = T0;
T0 += T1;
if (T0 < T2) {
xer_ca = 1;
} else {
xer_ca = 0;
}
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
RETURN();
}
/* add extended */
/* candidate for helper (too long) */
PPC_OP(adde)
{
T2 = T0;
T0 += T1 + xer_ca;
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
PPC_OP(addeo)
{
T2 = T0;
T0 += T1 + xer_ca;
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
RETURN();
}
/* add immediate */
PPC_OP(addi)
{
T0 += PARAM(1);
RETURN();
}
/* add immediate carrying */
PPC_OP(addic)
{
T1 = T0;
T0 += PARAM(1);
if (T0 < T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
/* add to minus one extended */
PPC_OP(addme)
{
T1 = T0;
T0 += xer_ca + (-1);
if (T1 != 0)
xer_ca = 1;
RETURN();
}
PPC_OP(addmeo)
{
T1 = T0;
T0 += xer_ca + (-1);
if (T1 & (T1 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T1 != 0)
xer_ca = 1;
RETURN();
}
/* add to zero extended */
PPC_OP(addze)
{
T1 = T0;
T0 += xer_ca;
if (T0 < T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
PPC_OP(addzeo)
{
T1 = T0;
T0 += xer_ca;
if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T0 < T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
/* divide word */
/* candidate for helper (too long) */
PPC_OP(divw)
{
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
Ts0 = (-1) * (T0 >> 31);
} else {
Ts0 /= Ts1;
}
RETURN();
}
PPC_OP(divwo)
{
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
xer_so = 1;
xer_ov = 1;
T0 = (-1) * (T0 >> 31);
} else {
xer_ov = 0;
Ts0 /= Ts1;
}
RETURN();
}
/* divide word unsigned */
PPC_OP(divwu)
{
if (T1 == 0) {
T0 = 0;
} else {
T0 /= T1;
}
RETURN();
}
PPC_OP(divwuo)
{
if (T1 == 0) {
xer_so = 1;
xer_ov = 1;
T0 = 0;
} else {
xer_ov = 0;
T0 /= T1;
}
RETURN();
}
/* multiply high word */
PPC_OP(mulhw)
{
Ts0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
RETURN();
}
/* multiply high word unsigned */
PPC_OP(mulhwu)
{
T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
RETURN();
}
/* multiply low immediate */
PPC_OP(mulli)
{
Ts0 *= SPARAM(1);
RETURN();
}
/* multiply low word */
PPC_OP(mullw)
{
T0 *= T1;
RETURN();
}
PPC_OP(mullwo)
{
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
if ((int32_t)res != res) {
xer_ov = 1;
xer_so = 1;
} else {
xer_ov = 0;
}
Ts0 = res;
RETURN();
}
/* negate */
PPC_OP(neg)
{
if (T0 != 0x80000000) {
Ts0 = -Ts0;
}
RETURN();
}
PPC_OP(nego)
{
if (T0 == 0x80000000) {
xer_ov = 1;
xer_so = 1;
} else {
xer_ov = 0;
Ts0 = -Ts0;
}
RETURN();
}
/* substract from */
PPC_OP(subf)
{
T0 = T1 - T0;
RETURN();
}
PPC_OP(subfo)
{
T2 = T0;
T0 = T1 - T0;
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
RETURN();
}
/* substract from carrying */
PPC_OP(subfc)
{
T0 = T1 - T0;
if (T0 <= T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
PPC_OP(subfco)
{
T2 = T0;
T0 = T1 - T0;
if (T0 <= T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
RETURN();
}
/* substract from extended */
/* candidate for helper (too long) */
PPC_OP(subfe)
{
T0 = T1 + ~T0 + xer_ca;
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
PPC_OP(subfeo)
{
T2 = T0;
T0 = T1 + ~T0 + xer_ca;
if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
/* substract from immediate carrying */
PPC_OP(subfic)
{
T0 = PARAM(1) + ~T0 + 1;
if (T0 <= PARAM(1)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
/* substract from minus one extended */
PPC_OP(subfme)
{
T0 = ~T0 + xer_ca - 1;
if (T0 != -1)
xer_ca = 1;
RETURN();
}
PPC_OP(subfmeo)
{
T1 = T0;
T0 = ~T0 + xer_ca - 1;
if (~T1 & (~T1 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T1 != -1)
xer_ca = 1;
RETURN();
}
/* substract from zero extended */
PPC_OP(subfze)
{
T1 = ~T0;
T0 = T1 + xer_ca;
if (T0 < T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
PPC_OP(subfzeo)
{
T1 = T0;
T0 = ~T0 + xer_ca;
if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
xer_ov = 1;
xer_so = 1;
} else {
xer_ov = 0;
}
if (T0 < ~T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
/*** Integer comparison ***/
/* compare */
PPC_OP(cmp)
{
if (Ts0 < Ts1) {
T0 = 0x08;
} else if (Ts0 > Ts1) {
T0 = 0x04;
} else {
T0 = 0x02;
}
RETURN();
}
/* compare immediate */
PPC_OP(cmpi)
{
if (Ts0 < SPARAM(1)) {
T0 = 0x08;
} else if (Ts0 > SPARAM(1)) {
T0 = 0x04;
} else {
T0 = 0x02;
}
RETURN();
}
/* compare logical */
PPC_OP(cmpl)
{
if (T0 < T1) {
T0 = 0x08;
} else if (T0 > T1) {
T0 = 0x04;
} else {
T0 = 0x02;
}
RETURN();
}
/* compare logical immediate */
PPC_OP(cmpli)
{
if (T0 < PARAM(1)) {
T0 = 0x08;
} else if (T0 > PARAM(1)) {
T0 = 0x04;
} else {
T0 = 0x02;
}
RETURN();
}
/*** Integer logical ***/
/* and */
PPC_OP(and)
{
T0 &= T1;
RETURN();
}
/* andc */
PPC_OP(andc)
{
T0 &= ~T1;
RETURN();
}
/* andi. */
PPC_OP(andi_)
{
T0 &= PARAM(1);
RETURN();
}
/* count leading zero */
PPC_OP(cntlzw)
{
T1 = T0;
for (T0 = 32; T1 > 0; T0--)
T1 = T1 >> 1;
RETURN();
}
/* eqv */
PPC_OP(eqv)
{
T0 = ~(T0 ^ T1);
RETURN();
}
/* extend sign byte */
PPC_OP(extsb)
{
Ts0 = s_ext8(Ts0);
RETURN();
}
/* extend sign half word */
PPC_OP(extsh)
{
Ts0 = s_ext16(Ts0);
RETURN();
}
/* nand */
PPC_OP(nand)
{
T0 = ~(T0 & T1);
RETURN();
}
/* nor */
PPC_OP(nor)
{
T0 = ~(T0 | T1);
RETURN();
}
/* or */
PPC_OP(or)
{
T0 |= T1;
RETURN();
}
/* orc */
PPC_OP(orc)
{
T0 |= ~T1;
RETURN();
}
/* ori */
PPC_OP(ori)
{
T0 |= PARAM(1);
RETURN();
}
/* xor */
PPC_OP(xor)
{
T0 ^= T1;
RETURN();
}
/* xori */
PPC_OP(xori)
{
T0 ^= PARAM(1);
RETURN();
}
/*** Integer rotate ***/
/* rotate left word immediate then mask insert */
PPC_OP(rlwimi)
{
T0 = rotl(T0, PARAM(1) & PARAM(2)) | (T0 & PARAM(3));
RETURN();
}
/* rotate left immediate then and with mask insert */
PPC_OP(rotlwi)
{
T0 = rotl(T0, PARAM(1));
RETURN();
}
PPC_OP(slwi)
{
T0 = T0 << PARAM(1);
RETURN();
}
PPC_OP(srwi)
{
T0 = T0 >> PARAM(1);
RETURN();
}
/* rotate left word then and with mask insert */
PPC_OP(rlwinm)
{
T0 = rotl(T0, PARAM(1)) & PARAM(2);
RETURN();
}
PPC_OP(rotl)
{
T0 = rotl(T0, T1);
RETURN();
}
PPC_OP(rlwnm)
{
T0 = rotl(T0, T1) & PARAM(1);
RETURN();
}
/*** Integer shift ***/
/* shift left word */
PPC_OP(slw)
{
if (T1 & 0x20) {
T0 = 0;
} else {
T0 = T0 << T1;
}
RETURN();
}
/* shift right algebraic word */
PPC_OP(sraw)
{
Ts0 = do_sraw(Ts0, T1);
RETURN();
}
/* shift right algebraic word immediate */
PPC_OP(srawi)
{
Ts1 = Ts0;
Ts0 = Ts0 >> PARAM(1);
if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
/* shift right word */
PPC_OP(srw)
{
if (T1 & 0x20) {
T0 = 0;
} else {
T0 = T0 >> T1;
}
RETURN();
}
/*** Floating-Point arithmetic ***/
/*** Floating-Point multiply-and-add ***/
/*** Floating-Point round & convert ***/
/*** Floating-Point compare ***/
/*** Floating-Point status & ctrl register ***/
/*** Integer load ***/
#define ld16x(x) s_ext16(ld16(x))
#define PPC_ILD_OPX(name, op) \
PPC_OP(l##name##x_z) \
{ \
T1 = op(T0); \
RETURN(); \
} \
PPC_OP(l##name##x) \
{ \
T0 += T1; \
T1 = op(T0); \
RETURN(); \
}
#define PPC_ILD_OP(name, op) \
PPC_OP(l##name##_z) \
{ \
T1 = op(SPARAM(1)); \
RETURN(); \
} \
PPC_OP(l##name) \
{ \
T0 += SPARAM(1); \
T1 = op(T0); \
RETURN(); \
} \
PPC_ILD_OPX(name, op)
PPC_ILD_OP(bz, ld8);
PPC_ILD_OP(ha, ld16x);
PPC_ILD_OP(hz, ld16);
PPC_ILD_OP(wz, ld32);
/*** Integer store ***/
#define PPC_IST_OPX(name, op) \
PPC_OP(st##name##x_z) \
{ \
op(T0, T1); \
RETURN(); \
} \
PPC_OP(st##name##x) \
{ \
T0 += T1; \
op(T0, T2); \
RETURN(); \
}
#define PPC_IST_OP(name, op) \
PPC_OP(st##name##_z) \
{ \
op(SPARAM(1), T0); \
RETURN(); \
} \
PPC_OP(st##name) \
{ \
T0 += SPARAM(1); \
op(T0, T1); \
RETURN(); \
} \
PPC_IST_OPX(name, op);
PPC_IST_OP(b, st8);
PPC_IST_OP(h, st16);
PPC_IST_OP(w, st32);
/*** Integer load and store with byte reverse ***/
PPC_ILD_OPX(hbr, ld16r);
PPC_ILD_OPX(wbr, ld32r);
PPC_IST_OPX(hbr, st16r);
PPC_IST_OPX(wbr, st32r);
/*** Integer load and store multiple ***/
PPC_OP(lmw)
{
do_lmw(PARAM(1), SPARAM(2) + T0);
RETURN();
}
PPC_OP(stmw)
{
do_stmw(PARAM(1), SPARAM(2) + T0);
RETURN();
}
/*** Integer load and store strings ***/
PPC_OP(lswi)
{
do_lsw(PARAM(1), PARAM(2), T0);
RETURN();
}
PPC_OP(lswx)
{
do_lsw(PARAM(1), T0, T1 + T2);
RETURN();
}
PPC_OP(stswi_z)
{
do_stsw(PARAM(1), PARAM(2), 0);
RETURN();
}
PPC_OP(stswi)
{
do_stsw(PARAM(1), PARAM(2), T0);
RETURN();
}
PPC_OP(stswx_z)
{
do_stsw(PARAM(1), T0, T1);
RETURN();
}
PPC_OP(stswx)
{
do_stsw(PARAM(1), T0, T1 + T2);
RETURN();
}
/*
* PPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Host registers definitions */
$DEFH T 3
/* PPC registers definitions */
$DEF gpr 32
$DEF fpr 32
$DEF crf 8
$DEF spr 1024
/* PPC registers <-> host registers move */
/* GPR */
$OP load_gpr_T0 gpr
{
T0 = regs->gpra;
RETURN();
}
$ENDOP
$OP load_gpr_T1 gpr
{
T1 = regs->gpra;
RETURN();
}
$ENDOP
$OP load_gpr_T2 gpr
{
T2 = regs->gpra;
RETURN();
}
$ENDOP
$OP store_T0_gpr gpr
{
regs->gpra = T0;
RETURN();
}
$ENDOP
$OP store_T1_gpr gpr
{
regs->gpra = T1;
RETURN();
}
$ENDOP
$OP store_gpr_P gpr PARAM
{
regs->gpra = PARAM(1);
RETURN();
}
$ENDOP
/* crf */
$OP load_crf_T0 crf
{
T0 = regs->crfa;
RETURN();
}
$ENDOP
$OP load_crf_T1 crf
{
T1 = regs->crfa;
RETURN();
}
$ENDOP
$OP store_T0_crf crf
{
regs->crfa = T0;
RETURN();
}
$ENDOP
$OP store_T1_crf crf
{
regs->crfa = T1;
RETURN();
}
$ENDOP
/* SPR */
$OP load_spr spr
{
T0 = regs->spra;
RETURN();
}
$ENDOP
$OP store_spr spr
{
regs->spra = T0;
RETURN();
}
$ENDOP
/* FPSCR */
$OP load_fpscr fpr
{
regs->fpra = do_load_fpscr();
RETURN();
}
$ENDOP
$OP store_fpscr fpr PARAM
{
do_store_fpscr(PARAM(1), regs->fpra);
RETURN();
}
$ENDOP
/*** Floating-point store ***/
/* candidate for helper (too long on x86 host) */
$OP stfd_z fpr PARAM
{
st64(SPARAM(1), regs->fpra);
RETURN();
}
$ENDOP
/* candidate for helper (too long on x86 host) */
$OP stfd fpr PARAM
{
T0 += SPARAM(1);
st64(T0, regs->fpra);
RETURN();
}
$ENDOP
/* candidate for helper (too long on x86 host) */
$OP stfdx_z fpr
{
st64(T0, regs->fpra);
RETURN();
}
$ENDOP
/* candidate for helper (too long on x86 host) */
$OP stfdx fpr
{
T0 += T1;
st64(T0, regs->fpra);
RETURN();
}
$ENDOP
/* candidate for helper (too long on x86 host) */
$OP lfd_z fpr PARAM
{
regs->fpra = ld64(SPARAM(1));
RETURN();
}
$ENDOP
/* candidate for helper (too long) */
$OP lfd fpr PARAM
{
T0 += SPARAM(1);
regs->fpra = ld64(T0);
RETURN();
}
$ENDOP
$OP lfdx_z fpr
{
regs->fpra = ld64(T0);
RETURN();
}
$ENDOP
$OP lfdx fpr
{
T0 += T1;
regs->fpra = ld64(T0);
RETURN();
}
$ENDOP
/*****************************************************************************/
/*
* PPC emulation for qemu: main translation routines.
*
* Copyright (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dyngen-exec.h"
#include "cpu.h"
#include "exec.h"
#include "disas.h"
//#define DO_SINGLE_STEP
//#define DO_STEP_FLUSH
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
#include "opc.h"
#undef DEF
NB_OPS,
};
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
#include "gen-op.h"
#include "select.h"
static uint8_t spr_access[1024 / 2];
/* internal defines */
typedef struct DisasContext {
struct TranslationBlock *tb;
uint32_t *nip;
uint32_t opcode;
int exception;
int retcode;
/* Time base */
uint32_t tb_offset;
int supervisor;
} DisasContext;
typedef struct opc_handler_t {
/* invalid bits */
uint32_t inval;
/* handler */
void (*handler)(DisasContext *ctx);
} opc_handler_t;
#define SET_RETVAL(n) \
do { \
if ((n) != 0) { \
ctx->exception = (n); \
} \
return; \
} while (0)
#define GET_RETVAL(func, __opcode) \
({ \
(func)(&ctx); \
ctx.exception; \
})
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
static void gen_##name (DisasContext *ctx); \
GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
static void gen_##name (DisasContext *ctx)
/* Instruction types */
enum {
PPC_INTEGER = 0x0001, /* CPU has integer operations instructions */
PPC_FLOAT = 0x0002, /* CPU has floating point operations instructions */
PPC_FLOW = 0x0004, /* CPU has flow control instructions */
PPC_MEM = 0x0008, /* CPU has virtual memory instructions */
PPC_MISC = 0x0010, /* CPU has spr/msr access instructions */
PPC_EXTERN = 0x0020, /* CPU has external control instructions */
PPC_SEGMENT = 0x0040, /* CPU has memory segment instructions */
};
typedef struct opcode_t {
unsigned char opc1, opc2, opc3;
uint32_t type;
opc_handler_t handler;
} opcode_t;
/* XXX: move that elsewhere */
extern FILE *logfile;
extern int loglevel;
/* XXX: shouldn't stay all alone here ! */
static int reserve = 0;
/*** Instruction decoding ***/
#define EXTRACT_HELPER(name, shift, nb) \
static inline uint32_t name (uint32_t opcode) \
{ \
return (opcode >> (shift)) & ((1 << (nb)) - 1); \
}
#define EXTRACT_SHELPER(name, shift, nb) \
static inline int32_t name (uint32_t opcode) \
{ \
return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1)); \
}
/* Opcode part 1 */
EXTRACT_HELPER(opc1, 26, 6);
/* Opcode part 2 */
EXTRACT_HELPER(opc2, 1, 5);
/* Opcode part 3 */
EXTRACT_HELPER(opc3, 6, 5);
/* Update Cr0 flags */
EXTRACT_HELPER(Rc, 0, 1);
/* Destination */
EXTRACT_HELPER(rD, 21, 5);
/* Source */
EXTRACT_HELPER(rS, 21, 5);
/* First operand */
EXTRACT_HELPER(rA, 16, 5);
/* Second operand */
EXTRACT_HELPER(rB, 11, 5);
/* Third operand */
EXTRACT_HELPER(rC, 6, 5);
/*** Get CRn ***/
EXTRACT_HELPER(crfD, 23, 3);
EXTRACT_HELPER(crfS, 18, 3);
EXTRACT_HELPER(crbD, 21, 5);
EXTRACT_HELPER(crbA, 16, 5);
EXTRACT_HELPER(crbB, 11, 5);
/* SPR / TBL */
EXTRACT_HELPER(SPR, 11, 10);
/*** Get constants ***/
EXTRACT_HELPER(IMM, 12, 8);
/* 16 bits signed immediate value */
EXTRACT_SHELPER(SIMM, 0, 16);
/* 16 bits unsigned immediate value */
EXTRACT_HELPER(UIMM, 0, 16);
/* Bit count */
EXTRACT_HELPER(NB, 11, 5);
/* Shift count */
EXTRACT_HELPER(SH, 11, 5);
/* Mask start */
EXTRACT_HELPER(MB, 6, 5);
/* Mask end */
EXTRACT_HELPER(ME, 1, 5);
EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(FM, 17, 8);
EXTRACT_HELPER(SR, 16, 4);
/*** Jump target decoding ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
static inline uint32_t LI (uint32_t opcode)
{
return (opcode >> 0) & 0x03FFFFFC;
}
static inline uint32_t BD (uint32_t opcode)
{
return (opcode >> 0) & 0xFFFC;
}
EXTRACT_HELPER(BO, 21, 5);
EXTRACT_HELPER(BI, 16, 5);
/* Absolute/relative address */
EXTRACT_HELPER(AA, 1, 1);
/* Link */
EXTRACT_HELPER(LK, 0, 1);
/* Create a mask between <start> and <end> bits */
static inline uint32_t MASK (uint32_t start, uint32_t end)
{
uint32_t ret;
ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
if (start > end)
return ~ret;
return ret;
}
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
__attribute__ ((section(".opcodes"), unused)) \
static opcode_t opc_##name = { \
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
.type = _typ, \
.handler = { \
.inval = invl, \
.handler = &gen_##name, \
}, \
}
#define GEN_OPCODE_MARK(name) \
__attribute__ ((section(".opcodes"), unused)) \
static opcode_t opc_##name = { \
.opc1 = 0xFF, \
.opc2 = 0xFF, \
.opc3 = 0xFF, \
.type = 0x00, \
.handler = { \
.inval = 0x00000000, \
.handler = NULL, \
}, \
}
/* Start opcode list */
GEN_OPCODE_MARK(start);
/* Invalid instruction */
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, 0)
{
/* Branch to next instruction to force nip update */
gen_op_b((uint32_t)ctx->nip);
SET_RETVAL(EXCP_INVAL);
}
static opc_handler_t invalid_handler = {
.inval = 0xFFFFFFFF,
.handler = gen_invalid,
};
/*** Integer arithmetic ***/
#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \
GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
SET_RETVAL(0); \
}
#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
gen_op_set_Rc0_ov(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
SET_RETVAL(0); \
}
#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
SET_RETVAL(0); \
}
#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
gen_op_set_Rc0_ov(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
SET_RETVAL(0); \
}
/* Two operands arithmetic functions */
#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \
__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \
__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
/* Two operands arithmetic functions with no overflow allowed */
#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \
__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
/* One operand arithmetic functions */
#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \
__GEN_INT_ARITH1(name, opc1, opc2, opc3) \
__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
/* add add. addo addo. */
GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08);
/* addc addc. addco addco. */
GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00);
/* adde adde. addeo addeo. */
GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04);
/* addme addme. addmeo addmeo. */
GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07);
/* addze addze. addzeo addzeo. */
GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06);
/* divw divw. divwo divwo. */
GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F);
/* divwu divwu. divwuo divwuo. */
GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E);
/* mulhw mulhw. */
GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02);
/* mulhwu mulhwu. */
GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
/* mullw mullw. mullwo mullwo. */
GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07);
/* neg neg. nego nego. */
GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03);
/* subf subf. subfo subfo. */
GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01);
/* subfc subfc. subfco subfco. */
GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00);
/* subfe subfe. subfeo subfeo. */
GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04);
/* subfme subfme. subfmeo subfmeo. */
GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
/* subfze subfze. subfzeo subfzeo. */
GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
/* addi */
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
int32_t simm = SIMM(ctx->opcode);
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(simm);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_addi(simm);
}
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* addic */
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_addic(SIMM(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* addic. */
GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_addic(SIMM(ctx->opcode));
gen_op_set_Rc0();
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
int32_t simm = SIMM(ctx->opcode);
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(simm << 16);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_addi(simm << 16);
}
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* mulli */
GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_mulli(SIMM(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* subfic */
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_subfic(SIMM(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/*** Integer comparison ***/
#define GEN_CMP(name, opc) \
GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
gen_op_store_T0_crf(crfD(ctx->opcode)); \
SET_RETVAL(0); \
}
/* cmp */
GEN_CMP(cmp, 0x00);
/* cmpi */
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_cmpi(SIMM(ctx->opcode));
gen_op_store_T0_crf(crfD(ctx->opcode));
SET_RETVAL(0);
}
/* cmpl */
GEN_CMP(cmpl, 0x01);
/* cmpli */
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_cmpli(UIMM(ctx->opcode));
gen_op_store_T0_crf(crfD(ctx->opcode));
SET_RETVAL(0);
}
/*** Integer logical ***/
#define __GEN_LOGICAL2(name, opc2, opc3) \
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_LOGICAL2(name, opc) \
__GEN_LOGICAL2(name, 0x1C, opc)
#define GEN_LOGICAL1(name, opc) \
GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_##name(); \
if (Rc(ctx->opcode) != 0) \
gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
/* and & and. */
GEN_LOGICAL2(and, 0x00);
/* andc & andc. */
GEN_LOGICAL2(andc, 0x01);
/* andi. */
GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_andi_(UIMM(ctx->opcode));
gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/* andis. */
GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_andi_(UIMM(ctx->opcode) << 16);
gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/* cntlzw */
GEN_LOGICAL1(cntlzw, 0x00);
/* eqv & eqv. */
GEN_LOGICAL2(eqv, 0x08);
/* extsb & extsb. */
GEN_LOGICAL1(extsb, 0x1D);
/* extsh & extsh. */
GEN_LOGICAL1(extsh, 0x1C);
/* nand & nand. */
GEN_LOGICAL2(nand, 0x0E);
/* nor & nor. */
GEN_LOGICAL2(nor, 0x03);
/* or & or. */
GEN_LOGICAL2(or, 0x0D);
/* orc & orc. */
GEN_LOGICAL2(orc, 0x0C);
/* xor & xor. */
GEN_LOGICAL2(xor, 0x09);
/* ori */
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
uint32_t uimm = UIMM(ctx->opcode);
#if 0
if (uimm == 0) {
if (rA(ctx->opcode) != rS(ctx->opcode)) {
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_T0_gpr(rA(ctx->opcode));
}
} else
#endif
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_ori(uimm);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
SET_RETVAL(0);
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
uint32_t uimm = UIMM(ctx->opcode);
#if 0
if (uimm == 0) {
if (rA(ctx->opcode) != rS(ctx->opcode)) {
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_T0_gpr(rA(ctx->opcode));
}
} else
#endif
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_ori(uimm << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
SET_RETVAL(0);
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_xori(UIMM(ctx->opcode));
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_xori(UIMM(ctx->opcode) << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/*** Integer rotate ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
uint32_t mb, me;
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
if (Rc(ctx->opcode) != 0)
gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
uint32_t mb, me, sh;
sh = SH(ctx->opcode);
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
if (loglevel > 0) {
fprintf(logfile, "%s sh=%u mb=%u me=%u MASK=0x%08x\n",
__func__, sh, mb, me, MASK(mb, me));
}
if (mb == 0) {
if (me == 31) {
gen_op_rotlwi(sh);
goto store;
} else if (me == (31 - sh)) {
gen_op_slwi(sh);
goto store;
} else if (sh == 0) {
gen_op_andi_(MASK(0, me));
goto store;
}
} else if (me == 31) {
if (sh == (32 - mb)) {
gen_op_srwi(mb);
goto store;
} else if (sh == 0) {
gen_op_andi_(MASK(mb, 31));
goto store;
}
}
gen_op_rlwinm(sh, MASK(mb, me));
store:
if (Rc(ctx->opcode) != 0)
gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
uint32_t mb, me;
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
if (mb == 0 && me == 31) {
gen_op_rotl();
} else
{
gen_op_rlwnm(MASK(mb, me));
}
if (Rc(ctx->opcode) != 0)
gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/*** Integer shift ***/
/* slw & slw. */
__GEN_LOGICAL2(slw, 0x18, 0x00);
/* sraw & sraw. */
__GEN_LOGICAL2(sraw, 0x18, 0x18);
/* srawi & srawi. */
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
if (Rc(ctx->opcode) != 0)
gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
SET_RETVAL(0);
}
/* srw & srw. */
__GEN_LOGICAL2(srw, 0x18, 0x10);
/*** Floating-Point arithmetic ***/
/* fadd */
GEN_HANDLER(fadd, 0x3F, 0x15, 0xFF, 0x000007C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fadds */
GEN_HANDLER(fadds, 0x3B, 0x15, 0xFF, 0x000007C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fdiv */
GEN_HANDLER(fdiv, 0x3F, 0x12, 0xFF, 0x000007C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fdivs */
GEN_HANDLER(fdivs, 0x3B, 0x12, 0xFF, 0x000007C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fmul */
GEN_HANDLER(fmul, 0x3F, 0x19, 0xFF, 0x0000F800, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fmuls */
GEN_HANDLER(fmuls, 0x3B, 0x19, 0xFF, 0x0000F800, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fres */
GEN_HANDLER(fres, 0x3B, 0x18, 0xFF, 0x001807C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* frsqrte */
GEN_HANDLER(frsqrte, 0x3F, 0x1A, 0xFF, 0x001807C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fsel */
GEN_HANDLER(fsel, 0x3F, 0x17, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fsub */
GEN_HANDLER(fsub, 0x3F, 0x14, 0xFF, 0x000007C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fsubs */
GEN_HANDLER(fsubs, 0x3B, 0x14, 0xFF, 0x000007C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* Optional: */
/* fsqrt */
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001807C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fsqrts */
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001807C0, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Floating-Point multiply-and-add ***/
/* fmadd */
GEN_HANDLER(fmadd, 0x3F, 0x1D, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fmadds */
GEN_HANDLER(fmadds, 0x3B, 0x1D, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fmsub */
GEN_HANDLER(fmsub, 0x3F, 0x1C, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fmsubs */
GEN_HANDLER(fmsubs, 0x3B, 0x1C, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fnmadd */
GEN_HANDLER(fnmadd, 0x3F, 0x1F, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fnmadds */
GEN_HANDLER(fnmadds, 0x3B, 0x1F, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fnmsub */
GEN_HANDLER(fnmsub, 0x3F, 0x1E, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fnmsubs */
GEN_HANDLER(fnmsubs, 0x3B, 0x1E, 0xFF, 0x00000000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Floating-Point round & convert ***/
/* fctiw */
GEN_HANDLER(fctiw, 0x3F, 0x0E, 0xFF, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fctiwz */
GEN_HANDLER(fctiwz, 0x3F, 0x0F, 0xFF, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* frsp */
GEN_HANDLER(frsp, 0x3F, 0x0C, 0xFF, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Floating-Point compare ***/
/* fcmpo */
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fcmpu */
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Floating-Point status & ctrl register ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
gen_op_load_fpscr(rD(ctx->opcode));
if (Rc(ctx->opcode)) {
/* Update CR1 */
}
SET_RETVAL(0);
}
/* mtfsb0 */
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* mtfsb1 */
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
gen_op_store_fpscr(FM(ctx->opcode), rB(ctx->opcode));
if (Rc(ctx->opcode)) {
/* Update CR1 */
}
SET_RETVAL(0);
}
/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Integer load ***/
#define GEN_ILDZ(width, opc) \
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0) { \
gen_op_l##width##_z(simm); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_l##width (simm); \
} \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_ILDZU(width, opc) \
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_l##width(SIMM(ctx->opcode)); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_ILDZUX(width, opc) \
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_l##width##x(); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_ILDZX(width, opc2, opc3) \
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
gen_op_l##width##x_z(); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_l##width##x(); \
} \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_ILD(width, op) \
GEN_ILDZ(width, op | 0x20) \
GEN_ILDZU(width, op | 0x21) \
GEN_ILDZUX(width, op | 0x01) \
GEN_ILDZX(width, 0x17, op | 0x00)
/* lbz lbzu lbzux lbzx */
GEN_ILD(bz, 0x02);
/* lha lhau lhaux lhax */
GEN_ILD(ha, 0x0A);
/* lhz lhzu lhzux lhzx */
GEN_ILD(hz, 0x08);
/* lwz lwzu lwzux lwzx */
GEN_ILD(wz, 0x00);
/*** Integer store ***/
#define GEN_IST(width, opc) \
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_st##width##_z(simm); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
gen_op_st##width(simm); \
} \
SET_RETVAL(0); \
}
#define GEN_ISTU(width, opc) \
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
gen_op_st##width(SIMM(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_ISTUX(width, opc) \
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_load_gpr_T2(rS(ctx->opcode)); \
gen_op_st##width##x(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_ISTX(width, opc2, opc3) \
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
{ \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
gen_op_st##width##x_z(); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_load_gpr_T2(rS(ctx->opcode)); \
gen_op_st##width##x(); \
} \
SET_RETVAL(0); \
}
#define GEN_ISTO(width, opc) \
GEN_IST(width, opc | 0x20) \
GEN_ISTU(width, opc | 0x21) \
GEN_ISTUX(width, opc | 0x01) \
GEN_ISTX(width, 0x17, opc | 0x00)
/* stb stbu stbux stbx */
GEN_ISTO(b, 0x06);
/* sth sthu sthux sthx */
GEN_ISTO(h, 0x0C);
/* stw stwu stwux stwx */
GEN_ISTO(w, 0x04);
/*** Integer load and store with byte reverse ***/
/* lhbrx */
GEN_ILDZX(hbr, 0x16, 0x18);
/* lwbrx */
GEN_ILDZX(wbr, 0x16, 0x10);
/* sthbrx */
GEN_ISTX(hbr, 0x16, 0x1C);
/* stwbrx */
GEN_ISTX(wbr, 0x16, 0x14);
/*** Integer load and store multiple ***/
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_lmw(rD(ctx->opcode), SIMM(ctx->opcode));
SET_RETVAL(0);
}
/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_stmw(rS(ctx->opcode), SIMM(ctx->opcode));
SET_RETVAL(0);
}
/*** Integer load and store strings ***/
/* lswi */
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
{
int nb = NB(ctx->opcode);
int start = rD(ctx->opcode);
int nr;
if (nb == 0)
nb = 32;
nr = nb / 4;
if ((start + nr) > 32) {
/* handle wrap around r0 */
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_lswi(start, 4 * (32 - start));
nb -= 4 * (32 - start);
start = 0;
}
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_lswi(start, nb);
SET_RETVAL(0);
}
/* lswx */
GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
{
gen_op_load_xer_bc();
gen_op_load_gpr_T1(rB(ctx->opcode));
if (rA(ctx->opcode) == 0) {
gen_op_set_T2(0);
} else {
gen_op_load_gpr_T2(rA(ctx->opcode));
}
gen_op_lswx(rD(ctx->opcode));
SET_RETVAL(0);
}
/* stswi */
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
{
int nb = NB(ctx->opcode);
int start = rS(ctx->opcode);
int nr;
if (nb == 0)
nb = 32;
nr = nb / 4;
if ((start + nr) > 32) {
/* handle wrap around r0 */
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_stswi(start, 4 * (32 - start));
nb -= 4 * (32 - start);
start = 0;
}
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_stswi(start, nb);
SET_RETVAL(0);
}
/* stswx */
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
{
gen_op_load_xer_bc();
gen_op_load_gpr_T1(rB(ctx->opcode));
if (rA(ctx->opcode) == 0) {
gen_op_set_T2(0);
} else {
gen_op_load_gpr_T2(rA(ctx->opcode));
}
gen_op_stswx(rS(ctx->opcode));
SET_RETVAL(0);
}
/*** Memory synchronisation ***/
/* eieio */
GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
{
/* Do a branch to next instruction */
gen_op_b((uint32_t)ctx->nip);
SET_RETVAL(EXCP_BRANCH);
}
/* isync */
GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
{
/* Do a branch to next instruction */
gen_op_b((uint32_t)ctx->nip);
SET_RETVAL(EXCP_BRANCH);
}
/* lwarx */
GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_MEM)
{
reserve = 1;
if (rA(ctx->opcode) == 0) {
gen_op_load_gpr_T0(rB(ctx->opcode));
gen_op_lwzx_z();
gen_op_set_reservation();
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_lwzx();
gen_op_set_reservation();
}
gen_op_store_T1_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* stwcx. */
GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_MEM)
{
if (reserve == 0) {
gen_op_reset_Rc0();
} else {
if (rA(ctx->opcode) == 0) {
gen_op_load_gpr_T0(rB(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_stwx_z();
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_load_gpr_T2(rS(ctx->opcode));
gen_op_stwx();
}
gen_op_set_Rc0_1();
gen_op_reset_reservation();
}
SET_RETVAL(0);
}
/* sync */
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
{
/* Do a branch to next instruction */
gen_op_b((uint32_t)ctx->nip);
SET_RETVAL(EXCP_BRANCH);
}
/*** Floating-point load ***/
#define GEN_LF(width, opc) \
GEN_HANDLER(lf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0) { \
gen_op_lf##width##_z(simm, rD(ctx->opcode)); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_lf##width(simm, rD(ctx->opcode)); \
} \
SET_RETVAL(0); \
}
#define GEN_LFU(width, opc) \
GEN_HANDLER(lf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_lf##width(SIMM(ctx->opcode), rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_LFUX(width, opc) \
GEN_HANDLER(lf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_lf##width##x(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_LFX(width, opc) \
GEN_HANDLER(lf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
gen_op_lf##width##x_z(rD(ctx->opcode)); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_lf##width##x(rD(ctx->opcode)); \
} \
SET_RETVAL(0); \
}
#define GEN_LDF(width, opc) \
GEN_LF(width, opc | 0x20) \
GEN_LFU(width, opc | 0x21) \
GEN_LFUX(width, opc | 0x01) \
GEN_LFX(width, opc | 0x00)
/* lfd lfdu lfdux lfdx */
GEN_LDF(d, 0x12);
/* lfs lfsu lfsux lfsx */
#define gen_op_lfs_z(a, b)
#define gen_op_lfs(a, b)
#define gen_op_lfsx_z(a)
#define gen_op_lfsx(a)
GEN_LDF(s, 0x10);
/*** Floating-point store ***/
#define GEN_STF(width, opc) \
GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0) { \
gen_op_stf##width##_z(simm, rS(ctx->opcode)); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_stf##width(simm, rS(ctx->opcode)); \
} \
SET_RETVAL(0); \
}
#define GEN_STFU(width, opc) \
GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_stf##width(SIMM(ctx->opcode), rS(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_STFUX(width, opc) \
GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_stf##width##x(rS(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
#define GEN_STFX(width, opc) \
GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
gen_op_stf##width##x_z(rS(ctx->opcode)); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_stf##width##x(rS(ctx->opcode)); \
} \
SET_RETVAL(0); \
}
#define GEN_STOF(width, opc) \
GEN_STF(width, opc | 0x20) \
GEN_STFU(width, opc | 0x21) \
GEN_STFUX(width, opc | 0x01) \
GEN_STFX(width, opc | 0x00)
/* stfd stfdu stfdux stfdx */
GEN_STOF(d, 0x16);
/* stfs stfsu stfsux stfsx */
#define gen_op_stfs_z(a, b)
#define gen_op_stfs(a, b)
#define gen_op_stfsx_z(a)
#define gen_op_stfsx(a)
GEN_STOF(s, 0x14);
/* Optional: */
/* stfiwx */
GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Floating-point move ***/
/* fabs */
GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fmr */
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fnabs */
GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/* fneg */
GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Branch ***/
#define GEN_BCOND(name, opc1, opc2, opc3, prologue, \
bl_ctr, b_ctr, bl_ctrz, b_ctrz, b, \
bl_ctr_true, b_ctr_true, bl_ctrz_true, b_ctrz_true, bl_true, b_true, \
bl_ctr_false, b_ctr_false, bl_ctrz_false, b_ctrz_false, bl_false, b_false) \
GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \
{ \
__attribute__ ((unused)) uint32_t target; \
uint32_t bo = BO(ctx->opcode); \
uint32_t bi = BI(ctx->opcode); \
uint32_t mask; \
prologue; \
if ((bo & 0x4) == 0) \
gen_op_dec_ctr(); \
if (bo & 0x10) { \
/* No CR condition */ \
switch (bo & 0x6) { \
case 0: \
if (LK(ctx->opcode)) { \
bl_ctr; \
} else { \
b_ctr; \
} \
break; \
case 2: \
if (LK(ctx->opcode)) { \
bl_ctrz; \
} else { \
b_ctrz; \
} \
break; \
case 4: \
case 6: \
b; \
if (LK(ctx->opcode)) \
gen_op_load_lr((uint32_t)ctx->nip); \
break; \
default: \
printf("ERROR: %s: unhandled ba case (%d)\n", __func__, bo); \
SET_RETVAL(EXCP_INVAL); \
break; \
} \
} else { \
mask = 1 << (3 - (bi & 0x03)); \
gen_op_load_crf_T0(bi >> 2); \
if (bo & 0x8) { \
switch (bo & 0x6) { \
case 0: \
if (LK(ctx->opcode)) { \
bl_ctr_true; \
} else { \
b_ctr_true; \
} \
break; \
case 2: \
if (LK(ctx->opcode)) { \
bl_ctrz_true; \
} else { \
b_ctrz_true; \
} \
break; \
case 4: \
case 6: \
if (LK(ctx->opcode)) { \
bl_true; \
} else { \
b_true; \
} \
break; \
default: \
printf("ERROR: %s: unhandled b case (%d)\n", __func__, bo); \
SET_RETVAL(EXCP_INVAL); \
break; \
} \
} else { \
switch (bo & 0x6) { \
case 0: \
if (LK(ctx->opcode)) { \
bl_ctr_false; \
} else { \
b_ctr_false; \
} \
break; \
case 2: \
if (LK(ctx->opcode)) { \
bl_ctrz_false; \
} else { \
b_ctrz_false; \
} \
break; \
case 4: \
case 6: \
if (LK(ctx->opcode)) { \
bl_false; \
} else { \
b_false; \
} \
break; \
default: \
printf("ERROR: %s: unhandled bn case (%d)\n", __func__, bo); \
SET_RETVAL(EXCP_INVAL); \
break; \
} \
} \
} \
SET_RETVAL(EXCP_BRANCH); \
}
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
uint32_t li = s_ext24(LI(ctx->opcode)), target;
if (AA(ctx->opcode) == 0)
target = (uint32_t)ctx->nip + li - 4;
else
target = s_ext24(LI(ctx->opcode));
gen_op_b(target);
if (LK(ctx->opcode))
gen_op_load_lr((uint32_t)ctx->nip);
SET_RETVAL(EXCP_BRANCH);
}
/* bc bca bcl bcla */
GEN_BCOND(bc, 0x10, 0xFF, 0xFF,
do {
uint32_t li = s_ext16(BD(ctx->opcode));
if (AA(ctx->opcode) == 0) {
target = (uint32_t)ctx->nip + li - 4;
} else {
target = li;
}
} while (0),
gen_op_bl_ctr((uint32_t)ctx->nip, target),
gen_op_b_ctr((uint32_t)ctx->nip, target),
gen_op_bl_ctrz((uint32_t)ctx->nip, target),
gen_op_b_ctrz((uint32_t)ctx->nip, target),
gen_op_b(target),
gen_op_bl_ctr_true((uint32_t)ctx->nip, target, mask),
gen_op_b_ctr_true((uint32_t)ctx->nip, target, mask),
gen_op_bl_ctrz_true((uint32_t)ctx->nip, target, mask),
gen_op_b_ctrz_true((uint32_t)ctx->nip, target, mask),
gen_op_bl_true((uint32_t)ctx->nip, target, mask),
gen_op_b_true((uint32_t)ctx->nip, target, mask),
gen_op_bl_ctr_false((uint32_t)ctx->nip, target, mask),
gen_op_b_ctr_false((uint32_t)ctx->nip, target, mask),
gen_op_bl_ctrz_false((uint32_t)ctx->nip, target, mask),
gen_op_b_ctrz_false((uint32_t)ctx->nip, target, mask),
gen_op_bl_false((uint32_t)ctx->nip, target, mask),
gen_op_b_false((uint32_t)ctx->nip, target, mask));
/* bcctr bcctrl */
GEN_BCOND(bcctr, 0x13, 0x10, 0x10, do { } while (0),
gen_op_bctrl_ctr((uint32_t)ctx->nip),
gen_op_bctr_ctr((uint32_t)ctx->nip),
gen_op_bctrl_ctrz((uint32_t)ctx->nip),
gen_op_bctr_ctrz((uint32_t)ctx->nip),
gen_op_bctr(),
gen_op_bctrl_ctr_true((uint32_t)ctx->nip, mask),
gen_op_bctr_ctr_true((uint32_t)ctx->nip, mask),
gen_op_bctrl_ctrz_true((uint32_t)ctx->nip, mask),
gen_op_bctr_ctrz_true((uint32_t)ctx->nip, mask),
gen_op_bctrl_true((uint32_t)ctx->nip, mask),
gen_op_bctr_true((uint32_t)ctx->nip, mask),
gen_op_bctrl_ctr_false((uint32_t)ctx->nip, mask),
gen_op_bctr_ctr_false((uint32_t)ctx->nip, mask),
gen_op_bctrl_ctrz_false((uint32_t)ctx->nip, mask),
gen_op_bctr_ctrz_false((uint32_t)ctx->nip, mask),
gen_op_bctrl_false((uint32_t)ctx->nip, mask),
gen_op_bctr_false((uint32_t)ctx->nip, mask))
/* bclr bclrl */
GEN_BCOND(bclr, 0x13, 0x10, 0x00, do { } while (0),
gen_op_blrl_ctr((uint32_t)ctx->nip),
gen_op_blr_ctr((uint32_t)ctx->nip),
gen_op_blrl_ctrz((uint32_t)ctx->nip),
gen_op_blr_ctrz((uint32_t)ctx->nip),
gen_op_blr(),
gen_op_blrl_ctr_true((uint32_t)ctx->nip, mask),
gen_op_blr_ctr_true((uint32_t)ctx->nip, mask),
gen_op_blrl_ctrz_true((uint32_t)ctx->nip, mask),
gen_op_blr_ctrz_true((uint32_t)ctx->nip, mask),
gen_op_blrl_true((uint32_t)ctx->nip, mask),
gen_op_blr_true((uint32_t)ctx->nip, mask),
gen_op_blrl_ctr_false((uint32_t)ctx->nip, mask),
gen_op_blr_ctr_false((uint32_t)ctx->nip, mask),
gen_op_blrl_ctrz_false((uint32_t)ctx->nip, mask),
gen_op_blr_ctrz_false((uint32_t)ctx->nip, mask),
gen_op_blrl_false((uint32_t)ctx->nip, mask),
gen_op_blr_false((uint32_t)ctx->nip, mask))
/*** Condition register logical ***/
#define GEN_CRLOGIC(op, opc) \
GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
{ \
gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \
gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \
gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \
gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \
gen_op_##op(); \
gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \
gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \
3 - (crbD(ctx->opcode) & 0x03)); \
gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \
SET_RETVAL(0); \
}
/* crand */
GEN_CRLOGIC(and, 0x08)
/* crandc */
GEN_CRLOGIC(andc, 0x04)
/* creqv */
GEN_CRLOGIC(eqv, 0x09)
/* crnand */
GEN_CRLOGIC(nand, 0x07)
/* crnor */
GEN_CRLOGIC(nor, 0x01)
/* cror */
GEN_CRLOGIC(or, 0x0E)
/* crorc */
GEN_CRLOGIC(orc, 0x0D)
/* crxor */
GEN_CRLOGIC(xor, 0x06)
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
gen_op_load_crf_T0(crfS(ctx->opcode));
gen_op_store_T0_crf(crfD(ctx->opcode));
SET_RETVAL(0);
}
/*** System linkage ***/
/* rfi (supervisor only) */
GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
{
SET_RETVAL(EXCP_INVAL);
}
/* sc */
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
{
gen_op_b((uint32_t)ctx->nip);
SET_RETVAL(EXCP_SYSCALL);
}
/*** Trap ***/
/* tw */
GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
{
SET_RETVAL(EXCP_INVAL);
}
/* twi */
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Processor control ***/
static inline int check_spr_access (int spr, int rw, int supervisor)
{
uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
rights = rights >> (2 * supervisor);
rights = rights >> rw;
return rights & 1;
}
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
gen_op_load_xer_cr();
gen_op_store_T0_crf(crfD(ctx->opcode));
gen_op_clear_xer_cr();
SET_RETVAL(0);
}
/* mfcr */
GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
{
gen_op_load_cr();
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* mfmsr */
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
if (!ctx->supervisor)
SET_RETVAL(EXCP_PRIV);
gen_op_load_msr();
gen_op_store_T0_gpr(rD(ctx->opcode));
SET_RETVAL(0);
}
/* mfspr */
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
{
uint32_t sprn = SPR(ctx->opcode);
if (check_spr_access(sprn, 0, ctx->supervisor) == 0)
SET_RETVAL(EXCP_PRIV);
/* XXX: make this more generic */
switch (sprn) {
case SPR_ENCODE(1):
if (loglevel > 0) {
fprintf(logfile, "LOAD XER at %p\n", ctx->nip - 1);
}
gen_op_load_xer();
break;
case SPR_ENCODE(268):
/* We need to update the time base before reading it */
gen_op_update_tb(ctx->tb_offset);
ctx->tb_offset = 0;
break;
case SPR_ENCODE(269):
gen_op_update_tb(ctx->tb_offset);
ctx->tb_offset = 0;
break;
default:
gen_op_load_spr(sprn);
break;
}
gen_op_store_T0_gpr(rD(ctx->opcode)); //
SET_RETVAL(0);
}
/* mftb */
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
{
uint32_t sprn = SPR(ctx->opcode);
if (check_spr_access(sprn, 0, ctx->supervisor) == 0)
SET_RETVAL(EXCP_PRIV);
switch (sprn) {
case SPR_ENCODE(268):
/* We need to update the time base before reading it */
gen_op_update_tb(ctx->tb_offset);
ctx->tb_offset = 0;
break;
case SPR_ENCODE(269):
gen_op_update_tb(ctx->tb_offset);
ctx->tb_offset = 0;
break;
default:
SET_RETVAL(EXCP_INVAL);
break;
}
SET_RETVAL(0);
}
/* mtcrf */
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_cr(CRM(ctx->opcode));
SET_RETVAL(0);
}
/* mtmsr */
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
if (!ctx->supervisor)
SET_RETVAL(EXCP_PRIV);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_msr();
/* Must stop the translation as machine state (may have) changed */
SET_RETVAL(EXCP_MTMSR);
}
/* mtspr */
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
{
uint32_t sprn = SPR(ctx->opcode);
if (check_spr_access(sprn, 1, ctx->supervisor) == 0)
SET_RETVAL(EXCP_PRIV);
gen_op_load_gpr_T0(rS(ctx->opcode));
if (sprn == SPR_ENCODE(1)) {
gen_op_store_xer();
} else {
gen_op_store_spr(sprn);
}
SET_RETVAL(0);
}
/*** Cache management ***/
/* For now, all those will be implemented as nop:
* this is valid, regarding the PowerPC specs...
*/
/* dcbf */
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x17, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* dcbi (Supervisor only) */
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* dcdst */
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* dcbt */
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x01, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* dcbtst */
GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x02, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* dcbz */
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x08, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* icbi */
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/* Optional: */
/* dcba */
GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_MEM)
{
SET_RETVAL(0);
}
/*** Segment register manipulation ***/
/* Supervisor only: */
/* mfsr */
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
SET_RETVAL(EXCP_INVAL);
}
/* mfsrin */
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x0010F001, PPC_SEGMENT)
{
SET_RETVAL(EXCP_INVAL);
}
/* mtsr */
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, PPC_SEGMENT)
{
SET_RETVAL(EXCP_INVAL);
}
/* mtsrin */
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x0010F001, PPC_SEGMENT)
{
SET_RETVAL(EXCP_INVAL);
}
/*** Lookaside buffer management ***/
/* Optional & supervisor only: */
/* tlbia */
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM)
{
SET_RETVAL(EXCP_INVAL);
}
/* tlbie */
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF8001, PPC_MEM)
{
SET_RETVAL(EXCP_INVAL);
}
/* tlbsync */
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, PPC_MEM)
{
SET_RETVAL(EXCP_INVAL);
}
/*** External control ***/
/* Optional: */
/* eciwx */
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
SET_RETVAL(EXCP_INVAL);
}
/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
SET_RETVAL(EXCP_INVAL);
}
/* End opcode list */
GEN_OPCODE_MARK(end);
/*****************************************************************************/
#include <string.h>
extern FILE *stderr;
void free (void *p);
int fflush (FILE *f);
/* Main ppc opcodes table:
* at init, all opcodes are invalids
*/
static opc_handler_t *ppc_opcodes[0x40];
/* Opcode types */
enum {
PPC_DIRECT = 0, /* Opcode routine */
PPC_INDIRECT = 1, /* Indirect opcode table */
};
static inline int is_indirect_opcode (void *handler)
{
return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
}
static inline opc_handler_t **ind_table(void *handler)
{
return (opc_handler_t **)((unsigned long)handler & ~3);
}
/* Opcodes tables creation */
static void fill_new_table (opc_handler_t **table, int len)
{
int i;
for (i = 0; i < len; i++)
table[i] = &invalid_handler;
}
static int create_new_table (opc_handler_t **table, unsigned char idx)
{
opc_handler_t **tmp;
tmp = malloc(0x20 * sizeof(opc_handler_t));
if (tmp == NULL)
return -1;
fill_new_table(tmp, 0x20);
table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
return 0;
}
static int insert_in_table (opc_handler_t **table, unsigned char idx,
opc_handler_t *handler)
{
if (table[idx] != &invalid_handler)
return -1;
table[idx] = handler;
return 0;
}
static int register_direct_insn (unsigned char idx, opc_handler_t *handler)
{
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
fprintf(stderr, "*** ERROR: opcode %02x already assigned in main "
"opcode table\n", idx);
return -1;
}
return 0;
}
static int register_ind_in_table (opc_handler_t **table,
unsigned char idx1, unsigned char idx2,
opc_handler_t *handler)
{
if (table[idx1] == &invalid_handler) {
if (create_new_table(table, idx1) < 0) {
fprintf(stderr, "*** ERROR: unable to create indirect table "
"idx=%02x\n", idx1);
return -1;
}
} else {
if (!is_indirect_opcode(table[idx1])) {
fprintf(stderr, "*** ERROR: idx %02x already assigned to a direct "
"opcode\n", idx1);
return -1;
}
}
if (handler != NULL &&
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
fprintf(stderr, "*** ERROR: opcode %02x already assigned in "
"opcode table %02x\n", idx2, idx1);
return -1;
}
return 0;
}
static int register_ind_insn (unsigned char idx1, unsigned char idx2,
opc_handler_t *handler)
{
int ret;
ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
return ret;
}
static int register_dblind_insn (unsigned char idx1, unsigned char idx2,
unsigned char idx3, opc_handler_t *handler)
{
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
fprintf(stderr, "*** ERROR: unable to join indirect table idx "
"[%02x-%02x]\n", idx1, idx2);
return -1;
}
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
handler) < 0) {
fprintf(stderr, "*** ERROR: unable to insert opcode "
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
return 0;
}
static int register_insn (opcode_t *insn)
{
if (insn->opc2 != 0xFF) {
if (insn->opc3 != 0xFF) {
if (register_dblind_insn(insn->opc1, insn->opc2, insn->opc3,
&insn->handler) < 0)
return -1;
} else {
if (register_ind_insn(insn->opc1, insn->opc2, &insn->handler) < 0)
return -1;
}
} else {
if (register_direct_insn(insn->opc1, &insn->handler) < 0)
return -1;
}
return 0;
}
static int test_opcode_table (opc_handler_t **table, int len)
{
int i, count, tmp;
for (i = 0, count = 0; i < len; i++) {
/* Consistency fixup */
if (table[i] == NULL)
table[i] = &invalid_handler;
if (table[i] != &invalid_handler) {
if (is_indirect_opcode(table[i])) {
tmp = test_opcode_table(ind_table(table[i]), 0x20);
if (tmp == 0) {
free(table[i]);
table[i] = &invalid_handler;
} else {
count++;
}
} else {
count++;
}
}
}
return count;
}
static void fix_opcode_tables (void)
{
if (test_opcode_table(ppc_opcodes, 0x40) == 0)
fprintf(stderr, "*** WARNING: no opcode defined !\n");
}
#define SPR_RIGHTS(rw, priv) ((2 * (priv)) + (rw))
#define SPR_UR SPR_RIGHTS(0, 0)
#define SPR_UW SPR_RIGHTS(1, 0)
#define SPR_SR SPR_RIGHTS(0, 1)
#define SPR_SW SPR_RIGHTS(1, 1)
#define spr_set_rights(spr, rights) \
do { \
spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \
} while (0)
static void init_spr_rights (void)
{
/* XER (SPR 1) */
spr_set_rights(SPR_ENCODE(1), SPR_UR | SPR_UW | SPR_SR | SPR_SW);
/* LR (SPR 8) */
spr_set_rights(SPR_ENCODE(8), SPR_UR | SPR_UW | SPR_SR | SPR_SW);
/* CTR (SPR 9) */
spr_set_rights(SPR_ENCODE(9), SPR_UR | SPR_UW | SPR_SR | SPR_SW);
/* TBL (SPR 268) */
spr_set_rights(SPR_ENCODE(268), SPR_UR | SPR_SR);
/* TBU (SPR 269) */
spr_set_rights(SPR_ENCODE(269), SPR_UR | SPR_SR);
/* DSISR (SPR 18) */
spr_set_rights(SPR_ENCODE(18), SPR_SR | SPR_SW);
/* DAR (SPR 19) */
spr_set_rights(SPR_ENCODE(19), SPR_SR | SPR_SW);
/* DEC (SPR 22) */
spr_set_rights(SPR_ENCODE(22), SPR_SR | SPR_SW);
/* SDR1 (SPR 25) */
spr_set_rights(SPR_ENCODE(25), SPR_SR | SPR_SW);
/* SPRG0 (SPR 272) */
spr_set_rights(SPR_ENCODE(272), SPR_SR | SPR_SW);
/* SPRG1 (SPR 273) */
spr_set_rights(SPR_ENCODE(273), SPR_SR | SPR_SW);
/* SPRG2 (SPR 274) */
spr_set_rights(SPR_ENCODE(274), SPR_SR | SPR_SW);
/* SPRG3 (SPR 275) */
spr_set_rights(SPR_ENCODE(275), SPR_SR | SPR_SW);
/* ASR (SPR 280) */
spr_set_rights(SPR_ENCODE(281), SPR_SR | SPR_SW);
/* EAR (SPR 282) */
spr_set_rights(SPR_ENCODE(282), SPR_SR | SPR_SW);
/* IBAT0U (SPR 528) */
spr_set_rights(SPR_ENCODE(528), SPR_SR | SPR_SW);
/* IBAT0L (SPR 529) */
spr_set_rights(SPR_ENCODE(529), SPR_SR | SPR_SW);
/* IBAT1U (SPR 530) */
spr_set_rights(SPR_ENCODE(530), SPR_SR | SPR_SW);
/* IBAT1L (SPR 531) */
spr_set_rights(SPR_ENCODE(531), SPR_SR | SPR_SW);
/* IBAT2U (SPR 532) */
spr_set_rights(SPR_ENCODE(532), SPR_SR | SPR_SW);
/* IBAT2L (SPR 533) */
spr_set_rights(SPR_ENCODE(533), SPR_SR | SPR_SW);
/* IBAT3U (SPR 534) */
spr_set_rights(SPR_ENCODE(534), SPR_SR | SPR_SW);
/* IBAT3L (SPR 535) */
spr_set_rights(SPR_ENCODE(535), SPR_SR | SPR_SW);
/* DBAT0U (SPR 536) */
spr_set_rights(SPR_ENCODE(536), SPR_SR | SPR_SW);
/* DBAT0L (SPR 537) */
spr_set_rights(SPR_ENCODE(537), SPR_SR | SPR_SW);
/* DBAT1U (SPR 538) */
spr_set_rights(SPR_ENCODE(538), SPR_SR | SPR_SW);
/* DBAT1L (SPR 539) */
spr_set_rights(SPR_ENCODE(539), SPR_SR | SPR_SW);
/* DBAT2U (SPR 540) */
spr_set_rights(SPR_ENCODE(540), SPR_SR | SPR_SW);
/* DBAT2L (SPR 541) */
spr_set_rights(SPR_ENCODE(541), SPR_SR | SPR_SW);
/* DBAT3U (SPR 542) */
spr_set_rights(SPR_ENCODE(542), SPR_SR | SPR_SW);
/* DBAT3L (SPR 543) */
spr_set_rights(SPR_ENCODE(543), SPR_SR | SPR_SW);
/* DABR (SPR 1013) */
spr_set_rights(SPR_ENCODE(1013), SPR_SR | SPR_SW);
/* FPECR (SPR 1022) */
spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW);
/* PIR (SPR 1023) */
spr_set_rights(SPR_ENCODE(1023), SPR_SR | SPR_SW);
/* PVR (SPR 287) */
spr_set_rights(SPR_ENCODE(287), SPR_SR);
/* TBL (SPR 284) */
spr_set_rights(SPR_ENCODE(284), SPR_SW);
/* TBU (SPR 285) */
spr_set_rights(SPR_ENCODE(285), SPR_SW);
}
/* PPC "main stream" common instructions */
#define PPC_COMMON (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \
PPC_MISC | PPC_EXTERN | PPC_SEGMENT)
typedef struct ppc_proc_t {
int flags;
void *specific;
} ppc_proc_t;
typedef struct ppc_def_t {
unsigned long pvr;
unsigned long pvr_mask;
ppc_proc_t *proc;
} ppc_def_t;
static ppc_proc_t ppc_proc_common = {
.flags = PPC_COMMON,
.specific = NULL,
};
static ppc_def_t ppc_defs[] =
{
/* Fallback */
{
.pvr = 0x00000000,
.pvr_mask = 0x00000000,
.proc = &ppc_proc_common,
},
};
static int create_ppc_proc (unsigned long pvr)
{
opcode_t *opc;
int i, flags;
fill_new_table(ppc_opcodes, 0x40);
for (i = 0; ; i++) {
if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) ==
(pvr & ppc_defs[i].pvr_mask)) {
flags = ppc_defs[i].proc->flags;
break;
}
}
for (opc = &opc_start + 1; opc != &opc_end; opc++) {
if ((opc->type & flags) != 0)
if (register_insn(opc) < 0) {
fprintf(stderr, "*** ERROR initializing PPC instruction "
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
opc->opc3);
return -1;
}
}
fix_opcode_tables();
return 0;
}
/*****************************************************************************/
uint32_t do_load_xer (void);
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
{
int i;
if (loglevel > 0) {
fprintf(logfile, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x\n",
env->nip, env->LR, env->CTR, do_load_xer());
for (i = 0; i < 32; i++) {
if ((i & 7) == 0)
fprintf(logfile, "GPR%02d:", i);
fprintf(logfile, " %08x", env->gpr[i]);
if ((i & 7) == 7)
fprintf(logfile, "\n");
}
fprintf(logfile, "CR: 0x");
for (i = 0; i < 8; i++)
fprintf(logfile, "%01x", env->crf[i]);
fprintf(logfile, " [");
for (i = 0; i < 8; i++) {
char a = '-';
if (env->crf[i] & 0x08)
a = 'L';
else if (env->crf[i] & 0x04)
a = 'G';
else if (env->crf[i] & 0x02)
a = 'E';
fprintf(logfile, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
}
fprintf(logfile, " ] ");
fprintf(logfile, "TB: 0x%08x %08x\n", env->spr[SPR_ENCODE(269)],
env->spr[SPR_ENCODE(268)]);
for (i = 0; i < 16; i++) {
if ((i & 3) == 0)
fprintf(logfile, "FPR%02d:", i);
fprintf(logfile, " %016llx", env->fpr[i]);
if ((i & 3) == 3)
fprintf(logfile, "\n");
}
fflush(logfile);
}
}
CPUPPCState *cpu_ppc_init(void)
{
CPUPPCState *env;
cpu_exec_init();
env = malloc(sizeof(CPUPPCState));
if (!env)
return NULL;
memset(env, 0, sizeof(CPUPPCState));
env->PVR = 0;
if (create_ppc_proc(0) < 0)
return NULL;
init_spr_rights();
return env;
}
void cpu_ppc_close(CPUPPCState *env)
{
/* Should also remove all opcode tables... */
free(env);
}
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
int search_pc)
{
DisasContext ctx;
opc_handler_t **table, *handler;
uint32_t pc_start;
uint16_t *gen_opc_end;
int j, lj = -1;
int ret = 0;
pc_start = tb->pc;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
ctx.nip = (uint32_t *)pc_start;
ctx.tb_offset = 0;
ctx.supervisor = msr_ip;
ctx.tb = tb;
ctx.exception = 0;
while (ret == 0 && gen_opc_ptr < gen_opc_end) {
if (search_pc) {
if (loglevel > 0)
fprintf(logfile, "Search PC...\n");
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = (uint32_t)ctx.nip;
gen_opc_instr_start[lj] = 1;
}
}
ctx.opcode = __be32_to_cpu(*ctx.nip);
#ifdef DEBUG_DISAS
if (loglevel > 0) {
fprintf(logfile, "----------------\n");
fprintf(logfile, "%p: translate opcode %08x\n",
ctx.nip, ctx.opcode);
}
#endif
ctx.nip++;
table = ppc_opcodes;
handler = table[opc1(ctx.opcode)];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
handler = table[opc2(ctx.opcode)];
if (is_indirect_opcode(handler)) {
table = ind_table(handler);
handler = table[opc3(ctx.opcode)];
}
}
/* Is opcode *REALLY* valid ? */
if ((ctx.opcode & handler->inval) != 0) {
if (loglevel > 0) {
if (handler->handler == &gen_invalid) {
fprintf(logfile, "invalid/unsupported opcode: "
"%02x -%02x - %02x (%08x)\n", opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode);
} else {
fprintf(logfile, "invalid bits: %08x for opcode: "
"%02x -%02x - %02x (%p)\n",
ctx.opcode & handler->inval, opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode),
handler->handler);
}
}
ret = GET_RETVAL(gen_invalid, ctx.opcode);
} else {
ret = GET_RETVAL(*(handler->handler), ctx.opcode);
}
ctx.tb_offset++;
#if defined (DO_SINGLE_STEP)
break;
#endif
}
#if defined (DO_STEP_FLUSH)
tb_flush();
#endif
/* We need to update the time base */
if (!search_pc)
gen_op_update_tb(ctx.tb_offset);
/* If we are in step-by-step mode, do a branch to the next instruction
* so the nip will be up-to-date
*/
#if defined (DO_SINGLE_STEP)
if (ret == 0) {
gen_op_b((uint32_t)ctx.nip);
ret = EXCP_BRANCH;
}
#endif
/* If the exeption isn't a PPC one,
* generate it now.
*/
if (ret != EXCP_BRANCH) {
gen_op_set_T0(0);
if ((ret & 0x2000) == 0)
gen_op_raise_exception(ret);
}
/* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
* do bad business and then qemu crashes !
*/
gen_op_set_T0(0);
/* Generate the return instruction */
gen_op_exit_tb();
*gen_opc_ptr = INDEX_op_end;
if (!search_pc)
tb->size = (uint32_t)ctx.nip - pc_start;
else
tb->size = 0;
// *gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
if (loglevel > 0) {
fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start));
disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0);
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
return 0;
}
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb)
{
return gen_intermediate_code_internal(env, tb, 0);
}
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb)
{
return gen_intermediate_code_internal(env, tb, 1);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册