From: Stuart B. <sd...@nt...> - 2008-03-04 16:22:59
|
Hi, Included is a patch to allow working HPPA Linux host support for QEMU. It should apply cleanly to QEMU 0.9.1. I have made only four changes since the removal of HPPA host support from HPPAQEMU CVS: * hppa_process_stubs() was emitting "be,n target(%sr0,%r1)", which was causing segfaults. Using sr4 instead seems to have fixed this. * testandset() has been rewritten. I'm not sure that it actually works, as the temporary non-atomic version didn't seem to cause problems! * flush_icache_range() seemed to have an off-by-one, which I've fixed. * the ppc64-softmmu target fails to link, so I've disabled it. With that, I've been able to run Debian/MIPS, Windows 98 and Win3.1! BTW, there seems to be a bug in SDL, which causes QEMU to segfault when quitting, at least when using the x11 driver. Unfortunately, I don't know what the cause of this is. I have produced a test for this, at http://permalink.gmane.org/gmane.linux.ports.parisc/151 I will try to update the patch to support the code in QEMU CVS, but that may take a while -- a new code generator, TCG (Tiny Code Generator) has been added, for which an HPPA target would have to be written. I will probably create a Git repository for this -- I will post more details here when I have them. Thanks to Randolph Chung for most of the work! -- and thanks also to everyone who's helped, whether it's with code review, encouragement, advice, or even a replacement C3K board! Cheers, -- Stuart Brady diff -urN qemu-0.9.1/configure qemu-0.9.1-hppa/configure --- qemu-0.9.1/configure 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/configure 2008-03-04 15:46:45.000000000 +0000 @@ -47,6 +47,9 @@ "Power Macintosh"|ppc|ppc64) cpu="powerpc" ;; + parisc|parisc64) + cpu="hppa" + ;; mips) cpu="mips" ;; @@ -522,7 +525,7 @@ if test -z "$target_list" ; then # these targets are portable if [ "$softmmu" = "yes" ] ; then - target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu sh4eb-softmmu cris-softmmu" + target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu m68k-softmmu sh4-softmmu sh4eb-softmmu cris-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then @@ -561,7 +564,7 @@ else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "mips64" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then +if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "mips64" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b" -o "$cpu" = "hppa"; then bigendian="yes" fi @@ -802,6 +805,9 @@ elif test "$cpu" = "powerpc" ; then echo "ARCH=ppc" >> $config_mak echo "#define HOST_PPC 1" >> $config_h +elif test "$cpu" = "hppa" ; then + echo "ARCH=hppa" >> $config_mak + echo "#define HOST_HPPA 1" >> $config_h elif test "$cpu" = "mips" ; then echo "ARCH=mips" >> $config_mak echo "#define HOST_MIPS 1" >> $config_h diff -urN qemu-0.9.1/cpu-all.h qemu-0.9.1-hppa/cpu-all.h --- qemu-0.9.1/cpu-all.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/cpu-all.h 2008-03-01 03:21:19.000000000 +0000 @@ -20,7 +20,7 @@ #ifndef CPU_ALL_H #define CPU_ALL_H -#if defined(__arm__) || defined(__sparc__) || defined(__mips__) +#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) #define WORDS_ALIGNED #endif @@ -947,6 +947,15 @@ return val; } +#elif defined(__hppa__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int val; + asm volatile ("mfctl %%cr16, %0" : "=r"(val)); + return val; +} + #elif defined(__ia64) static inline int64_t cpu_get_real_ticks(void) diff -urN qemu-0.9.1/cpu-exec.c qemu-0.9.1-hppa/cpu-exec.c --- qemu-0.9.1/cpu-exec.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/cpu-exec.c 2008-03-01 06:20:45.000000000 +0000 @@ -666,6 +666,15 @@ : /* no outputs */ : "r" (gen_func) : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); +#elif defined(__hppa__) + asm volatile ("bv %%r0(%0)\n" + "nop\n" + ".global exec_loop\n" + "exec_loop:\n" + : /* no outputs */ + : "r" (gen_func) + : "r1", "r20", "r21", "r22", "r23", + "r24", "r25", "r27", "r28"); #elif defined(__ia64) struct fptr { void *ip; @@ -1490,6 +1499,24 @@ is_write, &uc->uc_sigmask, puc); } +#elif defined(__hppa__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + struct siginfo *info = pinfo; + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.sc_iaoq[0]; + /* FIXME: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + #else #error host CPU specific signal handler needed diff -urN qemu-0.9.1/disas.c qemu-0.9.1-hppa/disas.c --- qemu-0.9.1/disas.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/disas.c 2008-02-29 15:42:04.000000000 +0000 @@ -279,6 +279,8 @@ print_insn = print_insn_m68k; #elif defined(__s390__) print_insn = print_insn_s390; +#elif defined(__hppa__) + print_insn = print_insn_hppa; #else fprintf(out, "0x%lx: Asm output not supported on this arch\n", (long) code); diff -urN qemu-0.9.1/dis-asm.h qemu-0.9.1-hppa/dis-asm.h --- qemu-0.9.1/dis-asm.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/dis-asm.h 2008-02-29 15:42:05.000000000 +0000 @@ -157,6 +157,10 @@ #define bfd_mach_ppc_7400 7400 bfd_arch_rs6000, /* IBM RS/6000 */ bfd_arch_hppa, /* HP PA RISC */ +#define bfd_mach_hppa10 10 +#define bfd_mach_hppa11 11 +#define bfd_mach_hppa20 20 +#define bfd_mach_hppa20w 25 bfd_arch_d10v, /* Mitsubishi D10V */ bfd_arch_z8k, /* Zilog Z8000 */ #define bfd_mach_z8001 1 diff -urN qemu-0.9.1/dyngen.c qemu-0.9.1-hppa/dyngen.c --- qemu-0.9.1/dyngen.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/dyngen.c 2008-03-01 06:27:31.000000000 +0000 @@ -117,6 +117,13 @@ #define elf_check_arch(x) ((x) == EM_68K) #define ELF_USES_RELOCA +#elif defined(HOST_HPPA) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_PARISC +#define elf_check_arch(x) ((x) == EM_PARISC) +#define ELF_USES_RELOCA + #elif defined(HOST_MIPS) #define ELF_CLASS ELFCLASS32 @@ -1221,7 +1228,7 @@ } else if (strstart(sym_name, "__op_gen_label", &p)) { snprintf(name, name_size, "gen_labels[param%s]", p); } else { -#ifdef HOST_SPARC +#if defined(HOST_SPARC) || defined(HOST_HPPA) if (sym_name[0] == '.') snprintf(name, name_size, "(long)(&__dot_%s)", @@ -1656,6 +1663,43 @@ error("rts expected at the end of %s", name); copy_size = p - p_start; } +#elif defined(HOST_HPPA) + { + uint8_t *p; + p = p_start; + while (p < p_end) { + uint32_t insn = get32((uint32_t *)p); + if (insn == 0x6bc23fd9 || + insn == 0x08030241 || + insn == 0x081e0243 || + (insn & 0x37de0000) == 0x37de0000 || + (insn & 0xffffc000) == 0x6fc10000) + p += 4; + else + break; + } + start_offset += p - p_start; + p_start = p; + p = p_end - 4; + + while (p > p_start) { + uint32_t insn = get32((uint32_t *)p); + if ((insn & 0xffffc000) == 0x347e0000 || + (insn & 0x0fc010e0) == 0x0fc01080 || + (insn & 0x37de0000) == 0x37de0000 || + insn == 0x48623fd9 || + insn == 0xe840c000 || + insn == 0xe840c002) + p -= 4; + else + break; + } + p += 4; + if (p <= p_start) + error("empty code for %s", name); + + copy_size = p - p_start; + } #elif defined(HOST_MIPS) || defined(HOST_MIPS64) { #define INSN_RETURN 0x03e00008 @@ -1741,7 +1785,7 @@ !strstart(sym_name, "__op_param", NULL) && !strstart(sym_name, "__op_jmp", NULL) && !strstart(sym_name, "__op_gen_label", NULL)) { -#if defined(HOST_SPARC) +#if defined(HOST_SPARC) || defined(HOST_HPPA) if (sym_name[0] == '.') { fprintf(outfile, "extern char __dot_%s __asm__(\"%s\");\n", @@ -1769,8 +1813,13 @@ } } +#ifdef __hppa__ + fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)__canonicalize_funcptr_for_compare(%s)+%d), %d);\n", + name, (int)(start_offset - offset), copy_size); +#else fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, (int)(start_offset - offset), copy_size); +#endif /* emit code offset information */ { @@ -2531,6 +2580,73 @@ } } } +#elif defined(HOST_HPPA) + { + char name[256]; + int type; + int addend; + int reloc_offset; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = get_rel_sym_name(rel); + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + get_reloc_expr(name, sizeof(name), sym_name); + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + reloc_offset = rel->r_offset - start_offset; + + switch(type) { + case R_PARISC_DIR21L: + fprintf(outfile, + " hppa_patch21l((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, name, addend); + break; + case R_PARISC_DIR14R: + fprintf(outfile, + " hppa_patch14r((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, name, addend); + break; + case R_PARISC_DIR17R: + fprintf(outfile, + " hppa_patch17r((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, name, addend); + break; + case R_PARISC_PCREL17F: + if (strstart(sym_name, "__op_gen_label", NULL)) { + fprintf(outfile, + " hppa_patch17f((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, name, addend); + } else { + fprintf(outfile, + " HPPA_RECORD_BRANCH(hppa_stubs, (uint32_t *)(gen_code_ptr + %d), %s);\n", + reloc_offset, name); + } + break; + case R_PARISC_DPREL21L: + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, " hppa_load_imm21l((uint32_t *)(gen_code_ptr + %d), param%s, %d);\n", + reloc_offset, p, addend); + else + fprintf(outfile, + " hppa_patch21l_dprel((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, name, addend); + break; + case R_PARISC_DPREL14R: + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, " hppa_load_imm14r((uint32_t *)(gen_code_ptr + %d), param%s, %d);\n", + reloc_offset, p, addend); + else + fprintf(outfile, + " hppa_patch14r_dprel((uint32_t *)(gen_code_ptr + %d), %s, %d);\n", + reloc_offset, name, addend); + break; + default: + error("unsupported hppa relocation (%d)", type); + } + } + } + } #elif defined(HOST_MIPS) || defined(HOST_MIPS64) { for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { @@ -2789,6 +2905,10 @@ } #endif +#ifdef HOST_HPPA + fprintf(outfile, " struct hppa_branch_stub *hppa_stubs = NULL;\n"); +#endif + fprintf(outfile, "\n" " gen_code_ptr = gen_code_buf;\n" @@ -2870,6 +2990,11 @@ " gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " "arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n"); #endif + +#ifdef HOST_HPPA + fprintf(outfile, "hppa_process_stubs(hppa_stubs, &gen_code_ptr);\n"); +#endif + /* flush instruction cache */ fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n"); diff -urN qemu-0.9.1/dyngen-exec.h qemu-0.9.1-hppa/dyngen-exec.h --- qemu-0.9.1/dyngen-exec.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/dyngen-exec.h 2008-02-29 15:41:51.000000000 +0000 @@ -124,6 +124,11 @@ #define AREG1 "r4" #define AREG2 "r5" #define AREG3 "r6" +#elif defined(__hppa__) +#define AREG0 "r17" +#define AREG1 "r14" +#define AREG2 "r15" +#define AREG3 "r16" #elif defined(__mips__) #define AREG0 "fp" #define AREG1 "s0" @@ -279,6 +284,11 @@ #elif defined(__mips__) #define EXIT_TB() asm volatile ("jr $ra") #define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at") +#elif defined(__hppa__) +#define EXIT_TB() asm volatile ("ldil L'exec_loop, %r1\n" \ + "ldo R'exec_loop(%r1), %r1\n" \ + "bv,n %r0(%r1)\n") +#define GOTO_LABEL_PARAM(n) asm volatile ("b,n " ASM_NAME(__op_gen_label) #n) #else #error unsupported CPU #endif diff -urN qemu-0.9.1/dyngen.h qemu-0.9.1-hppa/dyngen.h --- qemu-0.9.1/dyngen.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/dyngen.h 2008-03-01 06:31:27.000000000 +0000 @@ -62,6 +62,20 @@ asm volatile ("sync" : : : "memory"); asm volatile ("isync" : : : "memory"); } +#elif defined(__hppa__) +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + start &= ~31; + while (start <= stop) + { + asm volatile ("fdc 0(%0)\n" + "sync\n" + "fic 0(%%sr4, %0)\n" + "sync\n" + : : "r"(start) : "memory"); + start += 32; + } +} #elif defined(__alpha__) static inline void flush_icache_range(unsigned long start, unsigned long stop) { @@ -230,6 +244,138 @@ #endif /* __arm__ */ +#ifdef __hppa__ + +/* Field selection types defined by hppa */ +#define rnd(x) (((x)+0x1000)&~0x1fff) +/* lsel: select left 21 bits */ +#define lsel(v,a) (((v)+(a))>>11) +/* rsel: select right 11 bits */ +#define rsel(v,a) (((v)+(a))&0x7ff) +/* lrsel with rounding of addend to nearest 8k */ +#define lrsel(v,a) (((v)+rnd(a))>>11) +/* rrsel with rounding of addend to nearest 8k */ +#define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a))) + +#define mask(x,sz) ((x) & ~((1<<(sz))-1)) + +static inline int reassemble_14(int as14) +{ + return (((as14 & 0x1fff) << 1) | + ((as14 & 0x2000) >> 13)); +} + +static inline int reassemble_17(int as17) +{ + return (((as17 & 0x10000) >> 16) | + ((as17 & 0x0f800) << 5) | + ((as17 & 0x00400) >> 8) | + ((as17 & 0x003ff) << 3)); +} + +static inline int reassemble_21(int as21) +{ + return (((as21 & 0x100000) >> 20) | + ((as21 & 0x0ffe00) >> 8) | + ((as21 & 0x000180) << 7) | + ((as21 & 0x00007c) << 14) | + ((as21 & 0x000003) << 12)); +} + +struct hppa_branch_stub { + uint32_t *location; + long target; + struct hppa_branch_stub *next; +}; + +#define HPPA_RECORD_BRANCH(LIST, LOC, TARGET) \ +do { \ + struct hppa_branch_stub *stub = alloca(sizeof(struct hppa_branch_stub)); \ + stub->location = LOC; \ + stub->target = TARGET; \ + stub->next = LIST; \ + LIST = stub; \ +} while (0) + +static inline void hppa_patch21l(uint32_t *insn, int val, int addend) +{ + val = lrsel(val, addend); + *insn = mask(*insn, 21) | reassemble_21(val); +} + +static inline void hppa_patch14r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = mask(*insn, 14) | reassemble_14(val); +} + +static inline void hppa_patch17r(uint32_t *insn, int val, int addend) +{ + val = rrsel(val, addend); + *insn = (*insn & ~0x1f1ffd) | reassemble_17(val); +} + + +static inline void hppa_patch21l_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch21l(insn, val - dp, addend); +} + +static inline void hppa_patch14r_dprel(uint32_t *insn, int val, int addend) +{ + register unsigned int dp asm("r27"); + hppa_patch14r(insn, val - dp, addend); +} + +static inline void hppa_patch17f(uint32_t *insn, int val, int addend) +{ + int dot = (int)insn & ~0x3; + int v = ((val + addend) - dot - 8) / 4; + if (v > (1 << 16) || v < -(1 << 16)) { + printf("cannot fit branch to offset %d [%08x->%08x]\n", v, dot, val); + abort(); + } + *insn = (*insn & ~0x1f1ffd) | reassemble_17(v); +} + +static inline void hppa_load_imm21l(uint32_t *insn, int val, int addend) +{ + /* Transform addil L'sym(%dp) to ldil L'val, %r1 */ + *insn = 0x20200000 | reassemble_21(lrsel(val, 0)); +} + +static inline void hppa_load_imm14r(uint32_t *insn, int val, int addend) +{ + /* Transform ldw R'sym(%r1), %rN to ldo R'sym(%r1), %rN */ + hppa_patch14r(insn, val, addend); + /* HACK */ + if (addend == 0) + *insn = (*insn & ~0xfc000000) | (0x0d << 26); +} + +static inline void hppa_process_stubs(struct hppa_branch_stub *stub, + uint8_t **gen_code_pp) +{ + uint32_t *p = (uint32_t *)*gen_code_pp; + for (; stub != NULL; stub = stub->next) { + unsigned long l = (unsigned long)p; + /* stub: + * ldil L'target, %r1 + * be,n R'target(%sr4,%r1) + */ + *p++ = 0x20200000 | reassemble_21(lrsel(stub->target, 0)); + *p++ = 0xe0202002 | (reassemble_17(rrsel(stub->target, 0) >> 2)); + hppa_patch17f(stub->location, l, 0); + } + *gen_code_pp = (uint8_t *)p; +} + +/* supplied by libgcc */ +extern void *__canonicalize_funcptr_for_compare(void *); + +#endif + #ifdef __ia64 /* Patch instruction with "val" where "mask" has 1 bits. */ diff -urN qemu-0.9.1/exec-all.h qemu-0.9.1-hppa/exec-all.h --- qemu-0.9.1/exec-all.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/exec-all.h 2008-03-04 00:06:52.000000000 +0000 @@ -326,10 +326,10 @@ cache flushing, but slower because of indirect jump) */ #define GOTO_TB(opname, tbparam, n)\ do {\ - static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\ - static void __attribute__((used)) *__op_label ## n \ + static volatile void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\ + static volatile void __attribute__((used)) *__op_label ## n \ __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ + goto *(void *)(((volatile TranslationBlock *)tbparam)->tb_next[n]);\ label ## n: ;\ dummy_label ## n: ;\ } while (0) @@ -340,6 +340,28 @@ extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; +#if defined(__hppa__) + +typedef int spinlock_t[4]; +#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 } + +static inline void clearlock (spinlock_t *p) +{ + (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1; +} + +#else + +typedef int spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 + +static inline void clearlock (spinlock_t *p) +{ + *p = 0; +} + +#endif + #if defined(__powerpc__) static inline int testandset (int *p) { @@ -439,6 +461,27 @@ : "cc","memory"); return ret; } +#elif defined(__hppa__) + +#define __PA_LDCW_ALIGNMENT 16 + +static inline void *ldcw_align (void *p) { + unsigned long a = (unsigned long)p; + a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); + return (void *)a; +} + +static inline int testandset (spinlock_t *p) +{ + unsigned int ret; + p = ldcw_align(p); + __asm__ __volatile__("ldcw 0(%1),%0" + : "=r" (ret) + : "r" (p) + : "memory" ); + return !ret; +} + #elif defined(__ia64) #include <ia64intrin.h> @@ -471,10 +514,6 @@ #error unimplemented CPU support #endif -typedef int spinlock_t; - -#define SPIN_LOCK_UNLOCKED 0 - #if defined(CONFIG_USER_ONLY) static inline void spin_lock(spinlock_t *lock) { @@ -483,7 +522,7 @@ static inline void spin_unlock(spinlock_t *lock) { - *lock = 0; + clearlock(lock); } static inline int spin_trylock(spinlock_t *lock) diff -urN qemu-0.9.1/exec.c qemu-0.9.1-hppa/exec.c --- qemu-0.9.1/exec.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1-hppa/exec.c 2008-03-04 00:22:31.000000000 +0000 @@ -1214,7 +1214,7 @@ void cpu_interrupt(CPUState *env, int mask) { TranslationBlock *tb; - static int interrupt_lock; + static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; env->interrupt_request |= mask; /* if the cpu is currently executing code, we must unlink it and @@ -1223,7 +1223,7 @@ if (tb && !testandset(&interrupt_lock)) { env->current_tb = NULL; tb_reset_jump_recursive(tb); - interrupt_lock = 0; + clearlock(&interrupt_lock); } } diff -urN qemu-0.9.1/hppa-dis.c qemu-0.9.1-hppa/hppa-dis.c --- qemu-0.9.1/hppa-dis.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.9.1-hppa/hppa-dis.c 2008-03-04 02:57:50.000000000 +0000 @@ -0,0 +1,2834 @@ +/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. + Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003, + 2005 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-...@cs...). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "dis-asm.h" + +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2003 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-...@cs...). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _LIBHPPA_H +#define _LIBHPPA_H + +#define BYTES_IN_WORD 4 +#define PA_PAGESIZE 0x1000 + +/* The PA instruction set variants. */ +enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25}; + +/* HP PA-RISC relocation types */ + +enum hppa_reloc_field_selector_type + { + R_HPPA_FSEL = 0x0, + R_HPPA_LSSEL = 0x1, + R_HPPA_RSSEL = 0x2, + R_HPPA_LSEL = 0x3, + R_HPPA_RSEL = 0x4, + R_HPPA_LDSEL = 0x5, + R_HPPA_RDSEL = 0x6, + R_HPPA_LRSEL = 0x7, + R_HPPA_RRSEL = 0x8, + R_HPPA_NSEL = 0x9, + R_HPPA_NLSEL = 0xa, + R_HPPA_NLRSEL = 0xb, + R_HPPA_PSEL = 0xc, + R_HPPA_LPSEL = 0xd, + R_HPPA_RPSEL = 0xe, + R_HPPA_TSEL = 0xf, + R_HPPA_LTSEL = 0x10, + R_HPPA_RTSEL = 0x11, + R_HPPA_LTPSEL = 0x12, + R_HPPA_RTPSEL = 0x13 + }; + +/* /usr/include/reloc.h defines these to constants. We want to use + them in enums, so #undef them before we start using them. We might + be able to fix this another way by simply managing not to include + /usr/include/reloc.h, but currently GDB picks up these defines + somewhere. */ +#undef e_fsel +#undef e_lssel +#undef e_rssel +#undef e_lsel +#undef e_rsel +#undef e_ldsel +#undef e_rdsel +#undef e_lrsel +#undef e_rrsel +#undef e_nsel +#undef e_nlsel +#undef e_nlrsel +#undef e_psel +#undef e_lpsel +#undef e_rpsel +#undef e_tsel +#undef e_ltsel +#undef e_rtsel +#undef e_one +#undef e_two +#undef e_pcrel +#undef e_con +#undef e_plabel +#undef e_abs + +/* for compatibility */ +enum hppa_reloc_field_selector_type_alt + { + e_fsel = R_HPPA_FSEL, + e_lssel = R_HPPA_LSSEL, + e_rssel = R_HPPA_RSSEL, + e_lsel = R_HPPA_LSEL, + e_rsel = R_HPPA_RSEL, + e_ldsel = R_HPPA_LDSEL, + e_rdsel = R_HPPA_RDSEL, + e_lrsel = R_HPPA_LRSEL, + e_rrsel = R_HPPA_RRSEL, + e_nsel = R_HPPA_NSEL, + e_nlsel = R_HPPA_NLSEL, + e_nlrsel = R_HPPA_NLRSEL, + e_psel = R_HPPA_PSEL, + e_lpsel = R_HPPA_LPSEL, + e_rpsel = R_HPPA_RPSEL, + e_tsel = R_HPPA_TSEL, + e_ltsel = R_HPPA_LTSEL, + e_rtsel = R_HPPA_RTSEL, + e_ltpsel = R_HPPA_LTPSEL, + e_rtpsel = R_HPPA_RTPSEL + }; + +enum hppa_reloc_expr_type + { + R_HPPA_E_ONE = 0, + R_HPPA_E_TWO = 1, + R_HPPA_E_PCREL = 2, + R_HPPA_E_CON = 3, + R_HPPA_E_PLABEL = 7, + R_HPPA_E_ABS = 18 + }; + +/* for compatibility */ +enum hppa_reloc_expr_type_alt + { + e_one = R_HPPA_E_ONE, + e_two = R_HPPA_E_TWO, + e_pcrel = R_HPPA_E_PCREL, + e_con = R_HPPA_E_CON, + e_plabel = R_HPPA_E_PLABEL, + e_abs = R_HPPA_E_ABS + }; + + +/* Relocations for function calls must be accompanied by parameter + relocation bits. These bits describe exactly where the caller has + placed the function's arguments and where it expects to find a return + value. + + Both ELF and SOM encode this information within the addend field + of the call relocation. (Note this could break very badly if one + was to make a call like bl foo + 0x12345678). + + The high order 10 bits contain parameter relocation information, + the low order 22 bits contain the constant offset. */ + +#define HPPA_R_ARG_RELOC(a) \ + (((a) >> 22) & 0x3ff) +#define HPPA_R_CONSTANT(a) \ + ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22)) +#define HPPA_R_ADDEND(r, c) \ + (((r) << 22) + ((c) & 0x3fffff)) + + +/* Some functions to manipulate PA instructions. */ + +/* Declare the functions with the unused attribute to avoid warnings. */ +static inline int sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED; +static inline int sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED; +static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED; +static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED; +static inline bfd_signed_vma hppa_field_adjust + (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt) + ATTRIBUTE_UNUSED; +static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED; + + +/* The *sign_extend functions are used to assemble various bitfields + taken from an instruction and return the resulting immediate + value. */ + +static inline int +sign_extend (int x, int len) +{ + int signbit = (1 << (len - 1)); + int mask = (signbit << 1) - 1; + return ((x & mask) ^ signbit) - signbit; +} + +static inline int +low_sign_extend (int x, int len) +{ + return (x >> 1) - ((x & 1) << (len - 1)); +} + + +/* The re_assemble_* functions prepare an immediate value for + insertion into an opcode. pa-risc uses all sorts of weird bitfields + in the instruction to hold the value. */ + +static inline int +sign_unext (int x, int len) +{ + int len_ones; + + len_ones = (1 << len) - 1; + + return x & len_ones; +} + +static inline int +low_sign_unext (int x, int len) +{ + int temp; + int sign; + + sign = (x >> (len-1)) & 1; + + temp = sign_unext (x, len-1); + + return (temp << 1) | sign; +} + +static inline int +re_assemble_3 (int as3) +{ + return (( (as3 & 4) << (13-2)) + | ((as3 & 3) << (13+1))); +} + +static inline int +re_assemble_12 (int as12) +{ + return (( (as12 & 0x800) >> 11) + | ((as12 & 0x400) >> (10 - 2)) + | ((as12 & 0x3ff) << (1 + 2))); +} + +static inline int +re_assemble_14 (int as14) +{ + return (( (as14 & 0x1fff) << 1) + | ((as14 & 0x2000) >> 13)); +} + +static inline int +re_assemble_16 (int as16) +{ + int s, t; + + /* Unusual 16-bit encoding, for wide mode only. */ + t = (as16 << 1) & 0xffff; + s = (as16 & 0x8000); + return (t ^ s ^ (s >> 1)) | (s >> 15); +} + +static inline int +re_assemble_17 (int as17) +{ + return (( (as17 & 0x10000) >> 16) + | ((as17 & 0x0f800) << (16 - 11)) + | ((as17 & 0x00400) >> (10 - 2)) + | ((as17 & 0x003ff) << (1 + 2))); +} + +static inline int +re_assemble_21 (int as21) +{ + return (( (as21 & 0x100000) >> 20) + | ((as21 & 0x0ffe00) >> 8) + | ((as21 & 0x000180) << 7) + | ((as21 & 0x00007c) << 14) + | ((as21 & 0x000003) << 12)); +} + +static inline int +re_assemble_22 (int as22) +{ + return (( (as22 & 0x200000) >> 21) + | ((as22 & 0x1f0000) << (21 - 16)) + | ((as22 & 0x00f800) << (16 - 11)) + | ((as22 & 0x000400) >> (10 - 2)) + | ((as22 & 0x0003ff) << (1 + 2))); +} + + +/* Handle field selectors for PA instructions. + The L and R (and LS, RS etc.) selectors are used in pairs to form a + full 32 bit address. eg. + + LDIL L'start,%r1 ; put left part into r1 + LDW R'start(%r1),%r2 ; add r1 and right part to form address + + This function returns sign extended values in all cases. +*/ + +static inline bfd_signed_vma +hppa_field_adjust (bfd_vma sym_val, + bfd_signed_vma addend, + enum hppa_reloc_field_selector_type_alt r_field) +{ + bfd_signed_vma value; + + value = sym_val + addend; + switch (r_field) + { + case e_fsel: + /* F: No change. */ + break; + + case e_nsel: + /* N: null selector. I don't really understand what this is all + about, but HP's documentation says "this indicates that zero + bits are to be used for the displacement on the instruction. + This fixup is used to identify three-instruction sequences to + access data (for importing shared library data)." */ + value = 0; + break; + + case e_lsel: + case e_nlsel: + /* L: Select top 21 bits. */ + value = value >> 11; + break; + + case e_rsel: + /* R: Select bottom 11 bits. */ + value = value & 0x7ff; + break; + + case e_lssel: + /* LS: Round to nearest multiple of 2048 then select top 21 bits. */ + value = value + 0x400; + value = value >> 11; + break; + + case e_rssel: + /* RS: Select bottom 11 bits for LS. + We need to return a value such that 2048 * LS'x + RS'x == x. + ie. RS'x = x - ((x + 0x400) & -0x800) + this is just a sign extension from bit 21. */ + value = ((value & 0x7ff) ^ 0x400) - 0x400; + break; + + case e_ldsel: + /* LD: Round to next multiple of 2048 then select top 21 bits. + Yes, if we are already on a multiple of 2048, we go up to the + next one. RD in this case will be -2048. */ + value = value + 0x800; + value = value >> 11; + break; + + case e_rdsel: + /* RD: Set bits 0-20 to one. */ + value = value | -0x800; + break; + + case e_lrsel: + case e_nlrsel: + /* LR: L with rounding of the addend to nearest 8k. */ + value = sym_val + ((addend + 0x1000) & -0x2000); + value = value >> 11; + break; + + case e_rrsel: + /* RR: R with rounding of the addend to nearest 8k. + We need to return a value such that 2048 * LR'x + RR'x == x + ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800)) + . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000)) + . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */ + value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000); + break; + + default: + abort (); + } + return value; +} + +/* PA-RISC OPCODES */ +#define get_opcode(insn) (((insn) >> 26) & 0x3f) + +enum hppa_opcode_type +{ + /* None of the opcodes in the first group generate relocs, so we + aren't too concerned about them. */ + OP_SYSOP = 0x00, + OP_MEMMNG = 0x01, + OP_ALU = 0x02, + OP_NDXMEM = 0x03, + OP_SPOP = 0x04, + OP_DIAG = 0x05, + OP_FMPYADD = 0x06, + OP_UNDEF07 = 0x07, + OP_COPRW = 0x09, + OP_COPRDW = 0x0b, + OP_COPR = 0x0c, + OP_FLOAT = 0x0e, + OP_PRDSPEC = 0x0f, + OP_UNDEF15 = 0x15, + OP_UNDEF1d = 0x1d, + OP_FMPYSUB = 0x26, + OP_FPFUSED = 0x2e, + OP_SHEXDP0 = 0x34, + OP_SHEXDP1 = 0x35, + OP_SHEXDP2 = 0x36, + OP_UNDEF37 = 0x37, + OP_SHEXDP3 = 0x3c, + OP_SHEXDP4 = 0x3d, + OP_MULTMED = 0x3e, + OP_UNDEF3f = 0x3f, + + OP_LDIL = 0x08, + OP_ADDIL = 0x0a, + + OP_LDO = 0x0d, + OP_LDB = 0x10, + OP_LDH = 0x11, + OP_LDW = 0x12, + OP_LDWM = 0x13, + OP_STB = 0x18, + OP_STH = 0x19, + OP_STW = 0x1a, + OP_STWM = 0x1b, + + OP_LDD = 0x14, + OP_STD = 0x1c, + + OP_FLDW = 0x16, + OP_LDWL = 0x17, + OP_FSTW = 0x1e, + OP_STWL = 0x1f, + + OP_COMBT = 0x20, + OP_COMIBT = 0x21, + OP_COMBF = 0x22, + OP_COMIBF = 0x23, + OP_CMPBDT = 0x27, + OP_ADDBT = 0x28, + OP_ADDIBT = 0x29, + OP_ADDBF = 0x2a, + OP_ADDIBF = 0x2b, + OP_CMPBDF = 0x2f, + OP_BVB = 0x30, + OP_BB = 0x31, + OP_MOVB = 0x32, + OP_MOVIB = 0x33, + OP_CMPIBD = 0x3b, + + OP_COMICLR = 0x24, + OP_SUBI = 0x25, + OP_ADDIT = 0x2c, + OP_ADDI = 0x2d, + + OP_BE = 0x38, + OP_BLE = 0x39, + OP_BL = 0x3a +}; + + +/* Insert VALUE into INSN using R_FORMAT to determine exactly what + bits to change. */ + +static inline int +hppa_rebuild_insn (int insn, int value, int r_format) +{ + switch (r_format) + { + case 11: + return (insn & ~ 0x7ff) | low_sign_unext (value, 11); + + case 12: + return (insn & ~ 0x1ffd) | re_assemble_12 (value); + + + case 10: + return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8); + + case -11: + return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4); + + case 14: + return (insn & ~ 0x3fff) | re_assemble_14 (value); + + + case -10: + return (insn & ~ 0xfff1) | re_assemble_16 (value & -8); + + case -16: + return (insn & ~ 0xfff9) | re_assemble_16 (value & -4); + + case 16: + return (insn & ~ 0xffff) | re_assemble_16 (value); + + + case 17: + return (insn & ~ 0x1f1ffd) | re_assemble_17 (value); + + case 21: + return (insn & ~ 0x1fffff) | re_assemble_21 (value); + + case 22: + return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value); + + case 32: + return value; + + default: + abort (); + } + return insn; +} + +#endif /* _LIBHPPA_H */ +/* Table of opcodes for the PA-RISC. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-...@cs...). + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS/GDB 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ + +/* There are two kinds of delay slot nullification: normal which is + * controled by the nullification bit, and conditional, which depends + * on the direction of the branch and its success or failure. + * + * NONE is unfortunately #defined in the hiux system include files. + * #undef it away. + */ +#undef NONE +struct pa_opcode +{ + const char *name; + unsigned long int match; /* Bits that must be set... */ + unsigned long int mask; /* ... in these bits. */ + char *args; + enum pa_arch arch; + char flags; +}; + +/* Enables strict matching. Opcodes with match errors are skipped + when this bit is set. */ +#define FLAG_STRICT 0x1 + +/* + All hppa opcodes are 32 bits. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character for each operand of + the instruction. Characters used as a prefix allow any second character to + be used without conflicting with the main operand characters. + + Bit positions in this description follow HP usage of lsb = 31, + "at" is lsb of field. + + In the args field, the following characters must match exactly: + + '+,() ' + + In the args field, the following characters are unused: + + ' " - / 34 6789:; ' + '@ C M [\] ' + '` e g } ' + + Here are all the characters: + + ' !"#$%&'()*+-,./0123456789:;<=>?' + '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + '`abcdefghijklmnopqrstuvwxyz{|}~ ' + +Kinds of operands: + x integer register field at 15. + b integer register field at 10. + t integer register field at 31. + a integer register field at 10 and 15 (for PERMH) + 5 5 bit immediate at 15. + s 2 bit space specifier at 17. + S 3 bit space specifier at 18. + V 5 bit immediate value at 31 + i 11 bit immediate value at 31 + j 14 bit immediate value at 31 + k 21 bit immediate value at 31 + l 16 bit immediate value at 31 (wide mode only, unusual encoding). + n nullification for branch instructions + N nullification for spop and copr instructions + w 12 bit branch displacement + W 17 bit branch displacement (PC relative) + X 22 bit branch displacement (PC relative) + z 17 bit branch displacement (just a number, not an address) + +Also these: + + . 2 bit shift amount at 25 + * 4 bit shift amount at 25 + p 5 bit shift count at 26 (to support the SHD instruction) encoded as + 31-p + ~ 6 bit shift count at 20,22:26 encoded as 63-~. + P 5 bit bit position at 26 + q 6 bit bit position at 20,22:26 + T 5 bit field length at 31 (encoded as 32-T) + % 6 bit field length at 23,27:31 (variable extract/deposit) + | 6 bit field length at 19,27:31 (fixed extract/deposit) + A 13 bit immediate at 18 (to support the BREAK instruction) + ^ like b, but describes a control register + ! sar (cr11) register + D 26 bit immediate at 31 (to support the DIAG instruction) + $ 9 bit immediate at 28 (to support POPBTS) + + v 3 bit Special Function Unit identifier at 25 + O 20 bit Special Function Unit operation split between 15 bits at 20 + and 5 bits at 31 + o 15 bit Special Function Unit operation at 20 + 2 22 bit Special Function Unit operation split between 17 bits at 20 + and 5 bits at 31 + 1 15 bit Special Function Unit operation split between 10 bits at 20 + and 5 bits at 31 + 0 10 bit Special Function Unit operation split between 5 bits at 20 + and 5 bits at 31 + u 3 bit coprocessor unit identifier at 25 + F Source Floating Point Operand Format Completer encoded 2 bits at 20 + I Source Floating Point Operand Format Completer encoded 1 bits at 20 + (for 0xe format FP instructions) + G Destination Floating Point Operand Format Completer encoded 2 bits at 18 + H Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub' + (very similar to 'F') + + r 5 bit immediate value at 31 (for the break instruction) + (very similar to V above, except the value is unsigned instead of + low_sign_ext) + R 5 bit immediate value at 15 (for the ssm, rsm, probei instructions) + (same as r above, except the value is in a different location) + U 10 bit immediate value at 15 (for SSM, RSM on pa2.0) + Q 5 bit immediate value at 10 (a bit position specified in + the bb instruction. It's the same as r above, except the + value is in a different location) + B 5 bit immediate value at 10 (a bit position specified in + the bb instruction. Similar to Q, but 64 bit handling is + different. + Z %r1 -- implicit target of addil instruction. + L ,%r2 completer for new syntax branch + { Source format completer for fcnv + _ Destination format completer for fcnv + h cbit for fcmp + = gfx tests for ftest + d 14 bit offset for single precision FP long load/store. + # 14 bit offset for double precision FP load long/store. + J Yet another 14 bit offset for load/store with ma,mb completers. + K Yet another 14 bit offset for load/store with ma,mb completers. + y 16 bit offset for word aligned load/store (PA2.0 wide). + & 16 bit offset for dword aligned load/store (PA2.0 wide). + < 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + > 16 bit offset for load/store with ma,mb completers (PA2.0 wide). + Y %sr0,%r31 -- implicit target of be,l instruction. + @ implicit immediate value of 0 + +Completer operands all have 'c' as the prefix: + + cx indexed load and store completer. + cX indexed load and store completer. Like cx, but emits a space + after in disassembler. + cm short load and store completer. + cM short load and store completer. Like cm, but emits a space + after in disassembler. + cq long load and store completer (like cm, but inserted into a + different location in the target instruction). + cs store bytes short completer. + cA store bytes short completer. Like cs, but emits a space + after in disassembler. + ce long load/store completer for LDW/STW with a different encoding + than the others + cc load cache control hint + cd load and clear cache control hint + cC store cache control hint + co ordered access + + cp branch link and push completer + cP branch pop completer + cl branch link completer + cg branch gate completer + + cw read/write completer for PROBE + cW wide completer for MFCTL + cL local processor completer for cache control + cZ System Control Completer (to support LPA, LHA, etc.) + + ci correction completer for DCOR + ca add completer + cy 32 bit add carry completer + cY 64 bit add carry completer + cv signed overflow trap completer + ct trap on condition completer for ADDI, SUB + cT trap on condition completer for UADDCM + cb 32 bit borrow completer for SUB + cB 64 bit borrow completer for SUB + + ch left/right half completer + cH signed/unsigned saturation completer + cS signed/unsigned completer at 21 + cz zero/sign extension completer. + c* permutation completer + +Condition operands all have '?' as the prefix: + + ?f Floating point compare conditions (encoded as 5 bits at 31) + + ?a add conditions + ?A 64 bit add conditions + ?@ add branch conditions followed by nullify + ?d non-negated add branch conditions + ?D negated add branch conditions + ?w wide mode non-negated add branch conditions + ?W wide mode negated add branch conditions + + ?s compare/subtract conditions + ?S 64 bit compare/subtract conditions + ?t non-negated compare and branch conditions + ?n 32 bit compare and branch conditions followed by nullify + ?N 64 bit compare and branch conditions followed by nullify + ?Q 64 bit compare and branch conditions for CMPIB instruction + + ?l logical conditions + ?L 64 bit logical conditions + + ?b branch on bit conditions + ?B 64 bit branch on bit conditions + + ?x shift/extract/deposit conditions + ?X 64 bit shift/extract/deposit conditions + ?y shift/extract/deposit conditions followed by nullify for conditional + branches + + ?u unit conditions + ?U 64 bit unit conditions + +Floating point registers all have 'f' as a prefix: + + ft target register at 31 + fT target register with L/R halves at 31 + fa operand 1 register at 10 + fA operand 1 register with L/R halves at 10 + fX Same as fA, except prints a space before register during disasm + fb operand 2 register at 15 + fB operand 2 register with L/R halves at 15 + fC operand 3 register with L/R halves at 16:18,21:23 + fe Like fT, but encoding is different. + fE Same as fe, except prints a space before register during disasm. + fx target register at 15 (only for PA 2.0 long format FLDD/FSTD). + +Float registers for fmpyadd and fmpysub: + + fi mult operand 1 register at 10 + fj mult operand 2 register at 15 + fk mult target register at 20 + fl add/sub operand register at 25 + fm add/sub target register at 31 + +*/ + + +#if 0 +/* List of characters not to put a space after. Note that + "," is included, as the "spopN" operations use literal + commas in their completer sections. */ +static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}"; +#endif + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic be + consecutive. If they aren't, the assembler will bomb at runtime. + + * Immediate fields use pa_get_absolute_expression to parse the + string. It will generate a "bad expression" error if passed + a register name. Thus, register index variants of an opcode + need to precede immediate variants. + + * The disassembler does not care about the order of the opcodes + except in cases where implicit addressing is used. + + Here are the rules for ordering the opcodes of a mnemonic: + + 1) Opcodes with FLAG_STRICT should precede opcodes without + FLAG_STRICT. + + 2) Opcodes with FLAG_STRICT should be ordered as follows: + register index opcodes, short immediate opcodes, and finally + long immediate opcodes. When both pa10 and pa11 variants + of the same opcode are available, the pa10 opcode should + come first for correct architectural promotion. + + 3) When implicit addressing is available for an opcode, the + implicit opcode should precede the explicit opcode. + + 4) Opcodes without FLAG_STRICT should be ordered as follows: + register index opcodes, long immediate opcodes, and finally + short immediate opcodes. */ + +static const struct pa_opcode pa_opcodes[] = +{ + +/* Pseudo-instructions. */ + +{ "ldi", 0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */ +{ "ldi", 0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */ + +{ "cmpib", 0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT}, +{ "cmpib", 0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT}, +{ "comib", 0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comib", 0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ +{ "cmpb", 0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT}, +{ "cmpb", 0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT}, +{ "comb", 0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "comb", 0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ +{ "addb", 0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT}, +{ "addb", 0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addb", 0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0}, +{ "addib", 0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT}, +{ "addib", 0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +/* This entry is for the disassembler only. It will never be used by + assembler. */ +{ "addib", 0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ +{ "nop", 0x08000240, 0xffffffff, "", pa10, 0}, /* or 0,0,0 */ +{ "copy", 0x08000240, 0xffe0ffe0, "x,t", pa10, 0}, /* or r,0,t */ +{ "mtsar", 0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */ + +/* Loads and Stores for integer registers. */ + +{ "ldd", 0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT}, +{ "ldd", 0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT}, +{ "ldw", 0x48000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldw", 0x48000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldh", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldh", 0x44000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldh", 0x44000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "ldb", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, +{ "ldb", 0x40000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldb", 0x40000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "std", 0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "std", 0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT}, +{ "std", 0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stw", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT}, +{ "stw", 0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT}, +{ "stw", 0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT}, +{ "stw", 0x68000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stw", 0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "sth", 0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "sth", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "sth", 0x64000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "sth", 0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "stb", 0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stb", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, +{ "stb", 0x60000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stb", 0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc00c000, "j(b),x", pa10, 0}, +{ "ldwm", 0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0}, +{ "stwm", 0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, +{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, +{ "ldwa", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, +{ "ldwa", 0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldwa", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, +{ "ldcw", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, +{ "stwa", 0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, +{ "stwa", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, +{ "stby", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, +{ "ldda", 0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, +{ "ldda", 0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT}, +{ "ldcd", 0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, +{ "stda", 0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, +{ "ld... [truncated message content] |