mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 19:03:38 +08:00
HPPA (PA-RISC) host support
(Stuart Brady) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4199 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
339dea2774
commit
f54b3f920f
@ -128,6 +128,11 @@ ifeq ($(ARCH),alpha)
|
||||
CFLAGS+=-msmall-data
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),hppa)
|
||||
OP_CFLAGS=-O1 -fno-delayed-branch
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
CFLAGS+=-mno-sdata
|
||||
OP_CFLAGS+=-mno-sdata
|
||||
@ -267,6 +272,9 @@ endif
|
||||
ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
|
||||
LIBOBJS+=sh4-dis.o
|
||||
endif
|
||||
ifeq ($(findstring hppa, $(TARGET_BASE_ARCH) $(ARCH)),hppa)
|
||||
LIBOBJS+=hppa-dis.o
|
||||
endif
|
||||
ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390)
|
||||
LIBOBJS+=s390-dis.o
|
||||
endif
|
||||
|
7
configure
vendored
7
configure
vendored
@ -50,6 +50,9 @@ case "$cpu" in
|
||||
cris)
|
||||
cpu="cris"
|
||||
;;
|
||||
parisc|parisc64)
|
||||
cpu="hppa"
|
||||
;;
|
||||
ia64)
|
||||
cpu="ia64"
|
||||
;;
|
||||
@ -576,6 +579,7 @@ else
|
||||
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
if test "$cpu" = "armv4b" \
|
||||
-o "$cpu" = "hppa" \
|
||||
-o "$cpu" = "m68k" \
|
||||
-o "$cpu" = "mips" \
|
||||
-o "$cpu" = "mips64" \
|
||||
@ -865,6 +869,9 @@ elif test "$cpu" = "armv4l" ; then
|
||||
elif test "$cpu" = "cris" ; then
|
||||
echo "ARCH=cris" >> $config_mak
|
||||
echo "#define HOST_CRIS 1" >> $config_h
|
||||
elif test "$cpu" = "hppa" ; then
|
||||
echo "ARCH=hppa" >> $config_mak
|
||||
echo "#define HOST_HPPA 1" >> $config_h
|
||||
elif test "$cpu" = "ia64" ; then
|
||||
echo "ARCH=ia64" >> $config_mak
|
||||
echo "#define HOST_IA64 1" >> $config_h
|
||||
|
11
cpu-all.h
11
cpu-all.h
@ -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
|
||||
|
||||
@ -952,6 +952,15 @@ static inline int64_t cpu_get_real_ticks(void)
|
||||
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)
|
||||
|
29
cpu-exec.c
29
cpu-exec.c
@ -657,6 +657,17 @@ int cpu_exec(CPUState *env1)
|
||||
"o0", "o1", "o2", "o3", "o4", "o5",
|
||||
"l0", "l1", "l2", "l3", "l4", "l5",
|
||||
"l6", "l7");
|
||||
#elif defined(__hppa__)
|
||||
asm volatile ("ble 0(%%sr4,%1)\n"
|
||||
"copy %%r31,%%r18\n"
|
||||
"copy %%r28,%0\n"
|
||||
: "=r" (T0)
|
||||
: "r" (gen_func)
|
||||
: "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13",
|
||||
"r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "r29",
|
||||
"r30", "r31");
|
||||
#elif defined(__arm__)
|
||||
asm volatile ("mov pc, %0\n\t"
|
||||
".global exec_loop\n\t"
|
||||
@ -1488,6 +1499,24 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
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
|
||||
|
@ -157,6 +157,10 @@ enum bfd_architecture
|
||||
#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
|
||||
|
2
disas.c
2
disas.c
@ -279,6 +279,8 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
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);
|
||||
|
@ -124,6 +124,11 @@ extern int printf(const char *, ...);
|
||||
#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,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
#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 GOTO_LABEL_PARAM(n) asm volatile ("b,n " ASM_NAME(__op_gen_label) #n)
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
129
dyngen.c
129
dyngen.c
@ -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
|
||||
@ -1223,7 +1230,7 @@ int get_reloc_expr(char *name, int name_size, const char *sym_name)
|
||||
snprintf(name, name_size, "param%s", p);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef HOST_SPARC
|
||||
#if defined(HOST_SPARC) || defined(HOST_HPPA)
|
||||
if (sym_name[0] == '.')
|
||||
snprintf(name, name_size,
|
||||
"(long)(&__dot_%s)",
|
||||
@ -1661,6 +1668,43 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
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 || /* stw rp,-14(sp) */
|
||||
insn == 0x08030241 || /* copy r3,r1 */
|
||||
insn == 0x081e0243 || /* copy sp,r3 */
|
||||
(insn & 0xffffc000) == 0x37de0000 || /* ldo x(sp),sp */
|
||||
(insn & 0xffffc000) == 0x6fc10000) /* stwm r1,x(sp) */
|
||||
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 || /* ldo x(r3),sp */
|
||||
(insn & 0xffe0c000) == 0x4fc00000 || /* ldwm x(sp),rx */
|
||||
(insn & 0xffffc000) == 0x37de0000 || /* ldo x(sp),sp */
|
||||
insn == 0x48623fd9 || /* ldw -14(r3),rp */
|
||||
insn == 0xe840c000 || /* bv r0(rp) */
|
||||
insn == 0xe840c002) /* bv,n r0(rp) */
|
||||
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
|
||||
@ -1746,7 +1790,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
!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",
|
||||
@ -1774,8 +1818,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
}
|
||||
|
||||
#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 */
|
||||
{
|
||||
@ -2581,6 +2630,82 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_HPPA)
|
||||
{
|
||||
char relname[256];
|
||||
int type, is_label;
|
||||
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;
|
||||
is_label = get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = rel->r_addend;
|
||||
reloc_offset = rel->r_offset - start_offset;
|
||||
|
||||
if (is_label) {
|
||||
switch (type) {
|
||||
case R_PARISC_PCREL17F:
|
||||
fprintf(outfile,
|
||||
" tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
|
||||
reloc_offset, type, relname, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported hppa label relocation (%d)", type);
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case R_PARISC_DIR21L:
|
||||
fprintf(outfile,
|
||||
" hppa_patch21l((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_PARISC_DIR14R:
|
||||
fprintf(outfile,
|
||||
" hppa_patch14r((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
|
||||
reloc_offset, relname, 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, relname, addend);
|
||||
} else {
|
||||
fprintf(outfile,
|
||||
" HPPA_RECORD_BRANCH(hppa_stubs, (uint32_t *)(gen_code_ptr + %d), %s);\n",
|
||||
reloc_offset, relname);
|
||||
}
|
||||
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, relname, 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, relname, 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++) {
|
||||
|
2834
hppa-dis.c
Normal file
2834
hppa-dis.c
Normal file
File diff suppressed because it is too large
Load Diff
214
hppa.ld
Normal file
214
hppa.ld
Normal file
@ -0,0 +1,214 @@
|
||||
/* Default linker script, for normal executables */
|
||||
OUTPUT_FORMAT("elf32-hppa-linux", "elf32-hppa-linux",
|
||||
"elf32-hppa-linux")
|
||||
OUTPUT_ARCH(hppa:hppa1.1)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR("/usr/hppa-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
|
||||
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
|
||||
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
|
||||
.rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
|
||||
.rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
|
||||
.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
|
||||
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
|
||||
.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
|
||||
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
|
||||
.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
|
||||
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
|
||||
.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
|
||||
.rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
|
||||
.rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
|
||||
.rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
|
||||
.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
|
||||
.rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
|
||||
.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
|
||||
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
|
||||
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
} =0x08000240
|
||||
.text :
|
||||
{
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
KEEP (*(.text.*personality*))
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
} =0x08000240
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(.fini))
|
||||
} =0x08000240
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.sdata2 :
|
||||
{
|
||||
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
|
||||
}
|
||||
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
|
||||
.PARISC.unwind : { *(.PARISC.unwind) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x10000) + (. & (0x10000 - 1));
|
||||
/* Exception handling */
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||
/* Thread Local Storage sections */
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
}
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin*.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin*.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP (*(.jcr)) }
|
||||
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
.data :
|
||||
{
|
||||
PROVIDE ($global$ = .);
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
KEEP (*(.gnu.linkonce.d.*personality*))
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata :
|
||||
{
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
}
|
||||
_edata = .; PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss :
|
||||
{
|
||||
*(.dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
}
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections.
|
||||
FIXME: Why do we need it? When there is no .bss section, we don't
|
||||
pad the .data section. */
|
||||
. = ALIGN(. != 0 ? 32 / 8 : 1);
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
. = ALIGN(32 / 8);
|
||||
_end = .; PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
}
|
980
tcg/hppa/tcg-target.c
Normal file
980
tcg/hppa/tcg-target.c
Normal file
@ -0,0 +1,980 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
|
||||
"%r0",
|
||||
"%r1",
|
||||
"%rp",
|
||||
"%r3",
|
||||
"%r4",
|
||||
"%r5",
|
||||
"%r6",
|
||||
"%r7",
|
||||
"%r8",
|
||||
"%r9",
|
||||
"%r10",
|
||||
"%r11",
|
||||
"%r12",
|
||||
"%r13",
|
||||
"%r14",
|
||||
"%r15",
|
||||
"%r16",
|
||||
"%r17",
|
||||
"%r18",
|
||||
"%r19",
|
||||
"%r20",
|
||||
"%r21",
|
||||
"%r22",
|
||||
"%r23",
|
||||
"%r24",
|
||||
"%r25",
|
||||
"%r26",
|
||||
"%dp",
|
||||
"%ret0",
|
||||
"%ret1",
|
||||
"%sp",
|
||||
"%r31",
|
||||
};
|
||||
|
||||
static const int tcg_target_reg_alloc_order[] = {
|
||||
TCG_REG_R4,
|
||||
TCG_REG_R5,
|
||||
TCG_REG_R6,
|
||||
TCG_REG_R7,
|
||||
TCG_REG_R8,
|
||||
TCG_REG_R9,
|
||||
TCG_REG_R10,
|
||||
TCG_REG_R11,
|
||||
TCG_REG_R12,
|
||||
TCG_REG_R13,
|
||||
|
||||
TCG_REG_R17,
|
||||
TCG_REG_R14,
|
||||
TCG_REG_R15,
|
||||
TCG_REG_R16,
|
||||
};
|
||||
|
||||
static const int tcg_target_call_iarg_regs[4] = {
|
||||
TCG_REG_R26,
|
||||
TCG_REG_R25,
|
||||
TCG_REG_R24,
|
||||
TCG_REG_R23,
|
||||
};
|
||||
|
||||
static const int tcg_target_call_oarg_regs[2] = {
|
||||
TCG_REG_RET0,
|
||||
TCG_REG_RET1,
|
||||
};
|
||||
|
||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_target_long value, tcg_target_long addend)
|
||||
{
|
||||
switch (type) {
|
||||
case R_PARISC_PCREL17F:
|
||||
hppa_patch17f((uint32_t *)code_ptr, value, addend);
|
||||
break;
|
||||
default:
|
||||
tcg_abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* maximum number of register used for input function arguments */
|
||||
static inline int tcg_target_get_call_iarg_regs_count(int flags)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* parse target specific constraints */
|
||||
int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
{
|
||||
const char *ct_str;
|
||||
|
||||
ct_str = *pct_str;
|
||||
switch (ct_str[0]) {
|
||||
case 'r':
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
|
||||
break;
|
||||
case 'L': /* qemu_ld/st constraint */
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
|
||||
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R26);
|
||||
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R25);
|
||||
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R24);
|
||||
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R23);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
static inline int tcg_target_const_match(tcg_target_long val,
|
||||
const TCGArgConstraint *arg_ct)
|
||||
{
|
||||
int ct;
|
||||
|
||||
ct = arg_ct->ct;
|
||||
|
||||
/* TODO */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define INSN_OP(x) ((x) << 26)
|
||||
#define INSN_EXT3BR(x) ((x) << 13)
|
||||
#define INSN_EXT3SH(x) ((x) << 10)
|
||||
#define INSN_EXT4(x) ((x) << 6)
|
||||
#define INSN_EXT5(x) (x)
|
||||
#define INSN_EXT6(x) ((x) << 6)
|
||||
#define INSN_EXT7(x) ((x) << 6)
|
||||
#define INSN_EXT8A(x) ((x) << 6)
|
||||
#define INSN_EXT8B(x) ((x) << 5)
|
||||
#define INSN_T(x) (x)
|
||||
#define INSN_R1(x) ((x) << 16)
|
||||
#define INSN_R2(x) ((x) << 21)
|
||||
#define INSN_DEP_LEN(x) (32 - (x))
|
||||
#define INSN_SHDEP_CP(x) ((31 - (x)) << 5)
|
||||
#define INSN_SHDEP_P(x) ((x) << 5)
|
||||
#define INSN_COND(x) ((x) << 13)
|
||||
|
||||
#define COND_NEVER 0
|
||||
#define COND_EQUAL 1
|
||||
#define COND_LT 2
|
||||
#define COND_LTEQ 3
|
||||
#define COND_LTU 4
|
||||
#define COND_LTUEQ 5
|
||||
#define COND_SV 6
|
||||
#define COND_OD 7
|
||||
|
||||
|
||||
/* Logical ADD */
|
||||
#define ARITH_ADD (INSN_OP(0x02) | INSN_EXT6(0x28))
|
||||
#define ARITH_AND (INSN_OP(0x02) | INSN_EXT6(0x08))
|
||||
#define ARITH_OR (INSN_OP(0x02) | INSN_EXT6(0x09))
|
||||
#define ARITH_XOR (INSN_OP(0x02) | INSN_EXT6(0x0a))
|
||||
#define ARITH_SUB (INSN_OP(0x02) | INSN_EXT6(0x10))
|
||||
|
||||
#define SHD (INSN_OP(0x34) | INSN_EXT3SH(2))
|
||||
#define VSHD (INSN_OP(0x34) | INSN_EXT3SH(0))
|
||||
#define DEP (INSN_OP(0x35) | INSN_EXT3SH(3))
|
||||
#define ZDEP (INSN_OP(0x35) | INSN_EXT3SH(2))
|
||||
#define ZVDEP (INSN_OP(0x35) | INSN_EXT3SH(0))
|
||||
#define EXTRU (INSN_OP(0x34) | INSN_EXT3SH(6))
|
||||
#define EXTRS (INSN_OP(0x34) | INSN_EXT3SH(7))
|
||||
#define VEXTRS (INSN_OP(0x34) | INSN_EXT3SH(5))
|
||||
|
||||
#define SUBI (INSN_OP(0x25))
|
||||
#define MTCTL (INSN_OP(0x00) | INSN_EXT8B(0xc2))
|
||||
|
||||
#define BL (INSN_OP(0x3a) | INSN_EXT3BR(0))
|
||||
#define BLE_SR4 (INSN_OP(0x39) | (1 << 13))
|
||||
#define BV (INSN_OP(0x3a) | INSN_EXT3BR(6))
|
||||
#define BV_N (INSN_OP(0x3a) | INSN_EXT3BR(6) | 2)
|
||||
#define LDIL (INSN_OP(0x08))
|
||||
#define LDO (INSN_OP(0x0d))
|
||||
|
||||
#define LDB (INSN_OP(0x10))
|
||||
#define LDH (INSN_OP(0x11))
|
||||
#define LDW (INSN_OP(0x12))
|
||||
#define LDWM (INSN_OP(0x13))
|
||||
|
||||
#define STB (INSN_OP(0x18))
|
||||
#define STH (INSN_OP(0x19))
|
||||
#define STW (INSN_OP(0x1a))
|
||||
#define STWM (INSN_OP(0x1b))
|
||||
|
||||
#define COMBT (INSN_OP(0x20))
|
||||
#define COMBF (INSN_OP(0x22))
|
||||
|
||||
static int lowsignext(uint32_t val, int start, int length)
|
||||
{
|
||||
return (((val << 1) & ~(~0 << length)) |
|
||||
((val >> (length - 1)) & 1)) << start;
|
||||
}
|
||||
|
||||
static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
|
||||
{
|
||||
/* PA1.1 defines COPY as OR r,0,t */
|
||||
tcg_out32(s, ARITH_OR | INSN_T(ret) | INSN_R1(arg) | INSN_R2(TCG_REG_R0));
|
||||
|
||||
/* PA2.0 defines COPY as LDO 0(r),t
|
||||
* but hppa-dis.c is unaware of this definition */
|
||||
/* tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(arg) | reassemble_14(0)); */
|
||||
}
|
||||
|
||||
static inline void tcg_out_movi(TCGContext *s, TCGType type,
|
||||
int ret, tcg_target_long arg)
|
||||
{
|
||||
if (arg == (arg & 0x1fff)) {
|
||||
tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(TCG_REG_R0) |
|
||||
reassemble_14(arg));
|
||||
} else {
|
||||
tcg_out32(s, LDIL | INSN_R2(ret) |
|
||||
reassemble_21(lrsel((uint32_t)arg, 0)));
|
||||
if (arg & 0x7ff)
|
||||
tcg_out32(s, LDO | INSN_R1(ret) | INSN_R2(ret) |
|
||||
reassemble_14(rrsel((uint32_t)arg, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tcg_out_ld_raw(TCGContext *s, int ret,
|
||||
tcg_target_long arg)
|
||||
{
|
||||
tcg_out32(s, LDIL | INSN_R2(ret) |
|
||||
reassemble_21(lrsel((uint32_t)arg, 0)));
|
||||
tcg_out32(s, LDW | INSN_R1(ret) | INSN_R2(ret) |
|
||||
reassemble_14(rrsel((uint32_t)arg, 0)));
|
||||
}
|
||||
|
||||
static inline void tcg_out_ld_ptr(TCGContext *s, int ret,
|
||||
tcg_target_long arg)
|
||||
{
|
||||
tcg_out_ld_raw(s, ret, arg);
|
||||
}
|
||||
|
||||
static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset,
|
||||
int op)
|
||||
{
|
||||
if (offset == (offset & 0xfff))
|
||||
tcg_out32(s, op | INSN_R1(ret) | INSN_R2(addr) |
|
||||
reassemble_14(offset));
|
||||
else {
|
||||
fprintf(stderr, "unimplemented %s with offset %d\n", __func__, offset);
|
||||
tcg_abort();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
|
||||
int arg1, tcg_target_long arg2)
|
||||
{
|
||||
fprintf(stderr, "unimplemented %s\n", __func__);
|
||||
tcg_abort();
|
||||
}
|
||||
|
||||
static inline void tcg_out_st(TCGContext *s, TCGType type, int ret,
|
||||
int arg1, tcg_target_long arg2)
|
||||
{
|
||||
fprintf(stderr, "unimplemented %s\n", __func__);
|
||||
tcg_abort();
|
||||
}
|
||||
|
||||
static inline void tcg_out_arith(TCGContext *s, int t, int r1, int r2, int op)
|
||||
{
|
||||
tcg_out32(s, op | INSN_T(t) | INSN_R1(r1) | INSN_R2(r2));
|
||||
}
|
||||
|
||||
static inline void tcg_out_arithi(TCGContext *s, int t, int r1,
|
||||
tcg_target_long val, int op)
|
||||
{
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, val);
|
||||
tcg_out_arith(s, t, r1, TCG_REG_R20, op);
|
||||
}
|
||||
|
||||
static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
|
||||
{
|
||||
tcg_out_arithi(s, reg, reg, val, ARITH_ADD);
|
||||
}
|
||||
|
||||
static inline void tcg_out_nop(TCGContext *s)
|
||||
{
|
||||
tcg_out32(s, ARITH_OR | INSN_T(TCG_REG_R0) | INSN_R1(TCG_REG_R0) |
|
||||
INSN_R2(TCG_REG_R0));
|
||||
}
|
||||
|
||||
static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) {
|
||||
tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) |
|
||||
INSN_SHDEP_P(31) | INSN_DEP_LEN(8));
|
||||
}
|
||||
|
||||
static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) {
|
||||
tcg_out32(s, EXTRS | INSN_R1(ret) | INSN_R2(arg) |
|
||||
INSN_SHDEP_P(31) | INSN_DEP_LEN(16));
|
||||
}
|
||||
|
||||
static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) {
|
||||
if(ret != arg)
|
||||
tcg_out_mov(s, ret, arg);
|
||||
tcg_out32(s, DEP | INSN_R2(ret) | INSN_R1(ret) |
|
||||
INSN_SHDEP_CP(15) | INSN_DEP_LEN(8));
|
||||
tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(TCG_REG_R0) |
|
||||
INSN_R2(ret) | INSN_SHDEP_CP(8));
|
||||
}
|
||||
|
||||
static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg, int temp) {
|
||||
tcg_out32(s, SHD | INSN_T(temp) | INSN_R1(arg) |
|
||||
INSN_R2(arg) | INSN_SHDEP_CP(16));
|
||||
tcg_out32(s, DEP | INSN_R2(temp) | INSN_R1(temp) |
|
||||
INSN_SHDEP_CP(15) | INSN_DEP_LEN(8));
|
||||
tcg_out32(s, SHD | INSN_T(ret) | INSN_R1(arg) |
|
||||
INSN_R2(temp) | INSN_SHDEP_CP(8));
|
||||
}
|
||||
|
||||
static inline void tcg_out_call(TCGContext *s, void *func)
|
||||
{
|
||||
uint32_t val = (uint32_t)__canonicalize_funcptr_for_compare(func);
|
||||
tcg_out32(s, LDIL | INSN_R2(TCG_REG_R20) |
|
||||
reassemble_21(lrsel(val, 0)));
|
||||
tcg_out32(s, BLE_SR4 | INSN_R2(TCG_REG_R20) |
|
||||
reassemble_17(rrsel(val, 0) >> 2));
|
||||
tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
extern void __ldb_mmu(void);
|
||||
extern void __ldw_mmu(void);
|
||||
extern void __ldl_mmu(void);
|
||||
extern void __ldq_mmu(void);
|
||||
|
||||
extern void __stb_mmu(void);
|
||||
extern void __stw_mmu(void);
|
||||
extern void __stl_mmu(void);
|
||||
extern void __stq_mmu(void);
|
||||
|
||||
static void *qemu_ld_helpers[4] = {
|
||||
__ldb_mmu,
|
||||
__ldw_mmu,
|
||||
__ldl_mmu,
|
||||
__ldq_mmu,
|
||||
};
|
||||
|
||||
static void *qemu_st_helpers[4] = {
|
||||
__stb_mmu,
|
||||
__stw_mmu,
|
||||
__stl_mmu,
|
||||
__stq_mmu,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
|
||||
{
|
||||
int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
uint32_t *label1_ptr, *label2_ptr;
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 64
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
uint32_t *label3_ptr;
|
||||
#endif
|
||||
int addr_reg2;
|
||||
#endif
|
||||
|
||||
data_reg = *args++;
|
||||
if (opc == 3)
|
||||
data_reg2 = *args++;
|
||||
else
|
||||
data_reg2 = 0; /* surpress warning */
|
||||
addr_reg = *args++;
|
||||
#if TARGET_LONG_BITS == 64
|
||||
addr_reg2 = *args++;
|
||||
#endif
|
||||
mem_index = *args;
|
||||
s_bits = opc & 3;
|
||||
|
||||
r0 = TCG_REG_R26;
|
||||
r1 = TCG_REG_R25;
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
tcg_out_mov(s, r1, addr_reg);
|
||||
|
||||
tcg_out_mov(s, r0, addr_reg);
|
||||
|
||||
tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) |
|
||||
INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS));
|
||||
|
||||
tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1),
|
||||
ARITH_AND);
|
||||
|
||||
tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS,
|
||||
ARITH_AND);
|
||||
|
||||
tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD);
|
||||
tcg_out_arithi(s, r1, r1,
|
||||
offsetof(CPUState, tlb_table[mem_index][0].addr_read),
|
||||
ARITH_ADD);
|
||||
|
||||
tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW);
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
/* if equal, jump to label1 */
|
||||
label1_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) |
|
||||
INSN_COND(COND_EQUAL));
|
||||
tcg_out_mov(s, r0, addr_reg); /* delay slot */
|
||||
#else
|
||||
/* if not equal, jump to label3 */
|
||||
label3_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) |
|
||||
INSN_COND(COND_EQUAL));
|
||||
tcg_out_mov(s, r0, addr_reg); /* delay slot */
|
||||
|
||||
tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW);
|
||||
|
||||
/* if equal, jump to label1 */
|
||||
label1_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) |
|
||||
INSN_COND(COND_EQUAL));
|
||||
tcg_out_nop(s); /* delay slot */
|
||||
|
||||
/* label3: */
|
||||
*label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2);
|
||||
#endif
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
tcg_out_mov(s, TCG_REG_R26, addr_reg);
|
||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R25, mem_index);
|
||||
#else
|
||||
tcg_out_mov(s, TCG_REG_R26, addr_reg);
|
||||
tcg_out_mov(s, TCG_REG_R25, addr_reg2);
|
||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index);
|
||||
#endif
|
||||
|
||||
tcg_out_call(s, qemu_ld_helpers[s_bits]);
|
||||
|
||||
switch(opc) {
|
||||
case 0 | 4:
|
||||
tcg_out_ext8s(s, data_reg, TCG_REG_RET0);
|
||||
break;
|
||||
case 1 | 4:
|
||||
tcg_out_ext16s(s, data_reg, TCG_REG_RET0);
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
default:
|
||||
tcg_out_mov(s, data_reg, TCG_REG_RET0);
|
||||
break;
|
||||
case 3:
|
||||
tcg_abort();
|
||||
tcg_out_mov(s, data_reg, TCG_REG_RET0);
|
||||
tcg_out_mov(s, data_reg2, TCG_REG_RET1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* jump to label2 */
|
||||
label2_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2);
|
||||
|
||||
/* label1: */
|
||||
*label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2);
|
||||
|
||||
tcg_out_arithi(s, TCG_REG_R20, r1,
|
||||
offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read),
|
||||
ARITH_ADD);
|
||||
tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW);
|
||||
tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD);
|
||||
#else
|
||||
r0 = addr_reg;
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
bswap = 0;
|
||||
#else
|
||||
bswap = 1;
|
||||
#endif
|
||||
switch (opc) {
|
||||
case 0:
|
||||
tcg_out_ldst(s, data_reg, r0, 0, LDB);
|
||||
break;
|
||||
case 0 | 4:
|
||||
tcg_out_ldst(s, data_reg, r0, 0, LDB);
|
||||
tcg_out_ext8s(s, data_reg, data_reg);
|
||||
break;
|
||||
case 1:
|
||||
tcg_out_ldst(s, data_reg, r0, 0, LDH);
|
||||
if (bswap)
|
||||
tcg_out_bswap16(s, data_reg, data_reg);
|
||||
break;
|
||||
case 1 | 4:
|
||||
tcg_out_ldst(s, data_reg, r0, 0, LDH);
|
||||
if (bswap)
|
||||
tcg_out_bswap16(s, data_reg, data_reg);
|
||||
tcg_out_ext16s(s, data_reg, data_reg);
|
||||
break;
|
||||
case 2:
|
||||
tcg_out_ldst(s, data_reg, r0, 0, LDW);
|
||||
if (bswap)
|
||||
tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20);
|
||||
break;
|
||||
case 3:
|
||||
tcg_abort();
|
||||
if (!bswap) {
|
||||
tcg_out_ldst(s, data_reg, r0, 0, LDW);
|
||||
tcg_out_ldst(s, data_reg2, r0, 4, LDW);
|
||||
} else {
|
||||
tcg_out_ldst(s, data_reg, r0, 4, LDW);
|
||||
tcg_out_bswap32(s, data_reg, data_reg, TCG_REG_R20);
|
||||
tcg_out_ldst(s, data_reg2, r0, 0, LDW);
|
||||
tcg_out_bswap32(s, data_reg2, data_reg2, TCG_REG_R20);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tcg_abort();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
/* label2: */
|
||||
*label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
|
||||
{
|
||||
int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
uint32_t *label1_ptr, *label2_ptr;
|
||||
#endif
|
||||
#if TARGET_LONG_BITS == 64
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
uint32_t *label3_ptr;
|
||||
#endif
|
||||
int addr_reg2;
|
||||
#endif
|
||||
|
||||
data_reg = *args++;
|
||||
if (opc == 3)
|
||||
data_reg2 = *args++;
|
||||
else
|
||||
data_reg2 = 0; /* surpress warning */
|
||||
addr_reg = *args++;
|
||||
#if TARGET_LONG_BITS == 64
|
||||
addr_reg2 = *args++;
|
||||
#endif
|
||||
mem_index = *args;
|
||||
|
||||
s_bits = opc;
|
||||
|
||||
r0 = TCG_REG_R26;
|
||||
r1 = TCG_REG_R25;
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
tcg_out_mov(s, r1, addr_reg);
|
||||
|
||||
tcg_out_mov(s, r0, addr_reg);
|
||||
|
||||
tcg_out32(s, SHD | INSN_T(r1) | INSN_R1(TCG_REG_R0) | INSN_R2(r1) |
|
||||
INSN_SHDEP_CP(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS));
|
||||
|
||||
tcg_out_arithi(s, r0, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1),
|
||||
ARITH_AND);
|
||||
|
||||
tcg_out_arithi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS,
|
||||
ARITH_AND);
|
||||
|
||||
tcg_out_arith(s, r1, r1, TCG_AREG0, ARITH_ADD);
|
||||
tcg_out_arithi(s, r1, r1,
|
||||
offsetof(CPUState, tlb_table[mem_index][0].addr_write),
|
||||
ARITH_ADD);
|
||||
|
||||
tcg_out_ldst(s, TCG_REG_R20, r1, 0, LDW);
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
/* if equal, jump to label1 */
|
||||
label1_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(r0) |
|
||||
INSN_COND(COND_EQUAL));
|
||||
tcg_out_mov(s, r0, addr_reg); /* delay slot */
|
||||
#else
|
||||
/* if not equal, jump to label3 */
|
||||
label3_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, COMBF | INSN_R1(TCG_REG_R20) | INSN_R2(r0) |
|
||||
INSN_COND(COND_EQUAL));
|
||||
tcg_out_mov(s, r0, addr_reg); /* delay slot */
|
||||
|
||||
tcg_out_ldst(s, TCG_REG_R20, r1, 4, LDW);
|
||||
|
||||
/* if equal, jump to label1 */
|
||||
label1_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, COMBT | INSN_R1(TCG_REG_R20) | INSN_R2(addr_reg2) |
|
||||
INSN_COND(COND_EQUAL));
|
||||
tcg_out_nop(s); /* delay slot */
|
||||
|
||||
/* label3: */
|
||||
*label3_ptr |= reassemble_12((uint32_t *)s->code_ptr - label3_ptr - 2);
|
||||
#endif
|
||||
|
||||
tcg_out_mov(s, TCG_REG_R26, addr_reg);
|
||||
#if TARGET_LONG_BITS == 64
|
||||
tcg_out_mov(s, TCG_REG_R25, addr_reg2);
|
||||
if (opc == 3) {
|
||||
tcg_abort();
|
||||
tcg_out_mov(s, TCG_REG_R24, data_reg);
|
||||
tcg_out_mov(s, TCG_REG_R23, data_reg2);
|
||||
/* TODO: push mem_index */
|
||||
tcg_abort();
|
||||
} else {
|
||||
switch(opc) {
|
||||
case 0:
|
||||
tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) |
|
||||
INSN_SHDEP_P(31) | INSN_DEP_LEN(8));
|
||||
break;
|
||||
case 1:
|
||||
tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R24) | INSN_R2(data_reg) |
|
||||
INSN_SHDEP_P(31) | INSN_DEP_LEN(16));
|
||||
break;
|
||||
case 2:
|
||||
tcg_out_mov(s, TCG_REG_R24, data_reg);
|
||||
break;
|
||||
}
|
||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index);
|
||||
}
|
||||
#else
|
||||
if (opc == 3) {
|
||||
tcg_abort();
|
||||
tcg_out_mov(s, TCG_REG_R25, data_reg);
|
||||
tcg_out_mov(s, TCG_REG_R24, data_reg2);
|
||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R23, mem_index);
|
||||
} else {
|
||||
switch(opc) {
|
||||
case 0:
|
||||
tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) |
|
||||
INSN_SHDEP_P(31) | INSN_DEP_LEN(8));
|
||||
break;
|
||||
case 1:
|
||||
tcg_out32(s, EXTRU | INSN_R1(TCG_REG_R25) | INSN_R2(data_reg) |
|
||||
INSN_SHDEP_P(31) | INSN_DEP_LEN(16));
|
||||
break;
|
||||
case 2:
|
||||
tcg_out_mov(s, TCG_REG_R25, data_reg);
|
||||
break;
|
||||
}
|
||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R24, mem_index);
|
||||
}
|
||||
#endif
|
||||
tcg_out_call(s, qemu_st_helpers[s_bits]);
|
||||
|
||||
/* jump to label2 */
|
||||
label2_ptr = (uint32_t *)s->code_ptr;
|
||||
tcg_out32(s, BL | INSN_R2(TCG_REG_R0) | 2);
|
||||
|
||||
/* label1: */
|
||||
*label1_ptr |= reassemble_12((uint32_t *)s->code_ptr - label1_ptr - 2);
|
||||
|
||||
tcg_out_arithi(s, TCG_REG_R20, r1,
|
||||
offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write),
|
||||
ARITH_ADD);
|
||||
tcg_out_ldst(s, TCG_REG_R20, TCG_REG_R20, 0, LDW);
|
||||
tcg_out_arith(s, r0, r0, TCG_REG_R20, ARITH_ADD);
|
||||
#else
|
||||
r0 = addr_reg;
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
bswap = 0;
|
||||
#else
|
||||
bswap = 1;
|
||||
#endif
|
||||
switch (opc) {
|
||||
case 0:
|
||||
tcg_out_ldst(s, data_reg, r0, 0, STB);
|
||||
break;
|
||||
case 1:
|
||||
if (bswap) {
|
||||
tcg_out_bswap16(s, TCG_REG_R20, data_reg);
|
||||
data_reg = TCG_REG_R20;
|
||||
}
|
||||
tcg_out_ldst(s, data_reg, r0, 0, STH);
|
||||
break;
|
||||
case 2:
|
||||
if (bswap) {
|
||||
tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20);
|
||||
data_reg = TCG_REG_R20;
|
||||
}
|
||||
tcg_out_ldst(s, data_reg, r0, 0, STW);
|
||||
break;
|
||||
case 3:
|
||||
tcg_abort();
|
||||
if (!bswap) {
|
||||
tcg_out_ldst(s, data_reg, r0, 0, STW);
|
||||
tcg_out_ldst(s, data_reg2, r0, 4, STW);
|
||||
} else {
|
||||
tcg_out_bswap32(s, TCG_REG_R20, data_reg, TCG_REG_R20);
|
||||
tcg_out_ldst(s, TCG_REG_R20, r0, 4, STW);
|
||||
tcg_out_bswap32(s, TCG_REG_R20, data_reg2, TCG_REG_R20);
|
||||
tcg_out_ldst(s, TCG_REG_R20, r0, 0, STW);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tcg_abort();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
/* label2: */
|
||||
*label2_ptr |= reassemble_17((uint32_t *)s->code_ptr - label2_ptr - 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
|
||||
const int *const_args)
|
||||
{
|
||||
int c;
|
||||
|
||||
switch (opc) {
|
||||
case INDEX_op_exit_tb:
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RET0, args[0]);
|
||||
tcg_out32(s, BV_N | INSN_R2(TCG_REG_R18));
|
||||
break;
|
||||
case INDEX_op_goto_tb:
|
||||
if (s->tb_jmp_offset) {
|
||||
/* direct jump method */
|
||||
fprintf(stderr, "goto_tb direct\n");
|
||||
tcg_abort();
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R20, args[0]);
|
||||
tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20));
|
||||
s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
|
||||
} else {
|
||||
/* indirect jump method */
|
||||
tcg_out_ld_ptr(s, TCG_REG_R20,
|
||||
(tcg_target_long)(s->tb_next + args[0]));
|
||||
tcg_out32(s, BV_N | INSN_R2(TCG_REG_R20));
|
||||
}
|
||||
s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
|
||||
break;
|
||||
case INDEX_op_call:
|
||||
tcg_out32(s, BLE_SR4 | INSN_R2(args[0]));
|
||||
tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31);
|
||||
break;
|
||||
case INDEX_op_jmp:
|
||||
fprintf(stderr, "unimplemented jmp\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
case INDEX_op_br:
|
||||
fprintf(stderr, "unimplemented br\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
case INDEX_op_movi_i32:
|
||||
tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
|
||||
break;
|
||||
|
||||
case INDEX_op_ld8u_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], LDB);
|
||||
break;
|
||||
case INDEX_op_ld8s_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], LDB);
|
||||
tcg_out_ext8s(s, args[0], args[0]);
|
||||
break;
|
||||
case INDEX_op_ld16u_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], LDH);
|
||||
break;
|
||||
case INDEX_op_ld16s_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], LDH);
|
||||
tcg_out_ext16s(s, args[0], args[0]);
|
||||
break;
|
||||
case INDEX_op_ld_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], LDW);
|
||||
break;
|
||||
|
||||
case INDEX_op_st8_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], STB);
|
||||
break;
|
||||
case INDEX_op_st16_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], STH);
|
||||
break;
|
||||
case INDEX_op_st_i32:
|
||||
tcg_out_ldst(s, args[0], args[1], args[2], STW);
|
||||
break;
|
||||
|
||||
case INDEX_op_sub_i32:
|
||||
c = ARITH_SUB;
|
||||
goto gen_arith;
|
||||
case INDEX_op_and_i32:
|
||||
c = ARITH_AND;
|
||||
goto gen_arith;
|
||||
case INDEX_op_or_i32:
|
||||
c = ARITH_OR;
|
||||
goto gen_arith;
|
||||
case INDEX_op_xor_i32:
|
||||
c = ARITH_XOR;
|
||||
goto gen_arith;
|
||||
case INDEX_op_add_i32:
|
||||
c = ARITH_ADD;
|
||||
goto gen_arith;
|
||||
|
||||
case INDEX_op_shl_i32:
|
||||
tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) |
|
||||
lowsignext(0x1f, 0, 11));
|
||||
tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20));
|
||||
tcg_out32(s, ZVDEP | INSN_R2(args[0]) | INSN_R1(args[1]) |
|
||||
INSN_DEP_LEN(32));
|
||||
break;
|
||||
case INDEX_op_shr_i32:
|
||||
tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(args[2]));
|
||||
tcg_out32(s, VSHD | INSN_T(args[0]) | INSN_R1(TCG_REG_R0) |
|
||||
INSN_R2(args[1]));
|
||||
break;
|
||||
case INDEX_op_sar_i32:
|
||||
tcg_out32(s, SUBI | INSN_R1(TCG_REG_R20) | INSN_R2(args[2]) |
|
||||
lowsignext(0x1f, 0, 11));
|
||||
tcg_out32(s, MTCTL | INSN_R2(11) | INSN_R1(TCG_REG_R20));
|
||||
tcg_out32(s, VEXTRS | INSN_R1(args[0]) | INSN_R2(args[1]) |
|
||||
INSN_DEP_LEN(32));
|
||||
break;
|
||||
|
||||
case INDEX_op_mul_i32:
|
||||
fprintf(stderr, "unimplemented mul\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
case INDEX_op_mulu2_i32:
|
||||
fprintf(stderr, "unimplemented mulu2\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
case INDEX_op_div2_i32:
|
||||
fprintf(stderr, "unimplemented div2\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
case INDEX_op_divu2_i32:
|
||||
fprintf(stderr, "unimplemented divu2\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
fprintf(stderr, "unimplemented brcond\n");
|
||||
tcg_abort();
|
||||
break;
|
||||
|
||||
case INDEX_op_qemu_ld8u:
|
||||
tcg_out_qemu_ld(s, args, 0);
|
||||
break;
|
||||
case INDEX_op_qemu_ld8s:
|
||||
tcg_out_qemu_ld(s, args, 0 | 4);
|
||||
break;
|
||||
case INDEX_op_qemu_ld16u:
|
||||
tcg_out_qemu_ld(s, args, 1);
|
||||
break;
|
||||
case INDEX_op_qemu_ld16s:
|
||||
tcg_out_qemu_ld(s, args, 1 | 4);
|
||||
break;
|
||||
case INDEX_op_qemu_ld32u:
|
||||
tcg_out_qemu_ld(s, args, 2);
|
||||
break;
|
||||
|
||||
case INDEX_op_qemu_st8:
|
||||
tcg_out_qemu_st(s, args, 0);
|
||||
break;
|
||||
case INDEX_op_qemu_st16:
|
||||
tcg_out_qemu_st(s, args, 1);
|
||||
break;
|
||||
case INDEX_op_qemu_st32:
|
||||
tcg_out_qemu_st(s, args, 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unknown opcode 0x%x\n", opc);
|
||||
tcg_abort();
|
||||
}
|
||||
return;
|
||||
|
||||
gen_arith:
|
||||
tcg_out_arith(s, args[0], args[1], args[2], c);
|
||||
}
|
||||
|
||||
static const TCGTargetOpDef hppa_op_defs[] = {
|
||||
{ INDEX_op_exit_tb, { } },
|
||||
{ INDEX_op_goto_tb, { } },
|
||||
|
||||
{ INDEX_op_call, { "r" } },
|
||||
{ INDEX_op_jmp, { "r" } },
|
||||
{ INDEX_op_br, { } },
|
||||
|
||||
{ INDEX_op_mov_i32, { "r", "r" } },
|
||||
{ INDEX_op_movi_i32, { "r" } },
|
||||
{ INDEX_op_ld8u_i32, { "r", "r" } },
|
||||
{ INDEX_op_ld8s_i32, { "r", "r" } },
|
||||
{ INDEX_op_ld16u_i32, { "r", "r" } },
|
||||
{ INDEX_op_ld16s_i32, { "r", "r" } },
|
||||
{ INDEX_op_ld_i32, { "r", "r" } },
|
||||
{ INDEX_op_st8_i32, { "r", "r" } },
|
||||
{ INDEX_op_st16_i32, { "r", "r" } },
|
||||
{ INDEX_op_st_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_add_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_sub_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_and_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_or_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_xor_i32, { "r", "r", "r" } },
|
||||
|
||||
{ INDEX_op_shl_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_shr_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_sar_i32, { "r", "r", "r" } },
|
||||
|
||||
{ INDEX_op_brcond_i32, { "r", "r" } },
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
{ INDEX_op_qemu_ld8u, { "r", "L" } },
|
||||
{ INDEX_op_qemu_ld8s, { "r", "L" } },
|
||||
{ INDEX_op_qemu_ld16u, { "r", "L" } },
|
||||
{ INDEX_op_qemu_ld16s, { "r", "L" } },
|
||||
{ INDEX_op_qemu_ld32u, { "r", "L" } },
|
||||
{ INDEX_op_qemu_ld64, { "r", "r", "L" } },
|
||||
|
||||
{ INDEX_op_qemu_st8, { "L", "L" } },
|
||||
{ INDEX_op_qemu_st16, { "L", "L" } },
|
||||
{ INDEX_op_qemu_st32, { "L", "L" } },
|
||||
{ INDEX_op_qemu_st64, { "L", "L", "L" } },
|
||||
#else
|
||||
{ INDEX_op_qemu_ld8u, { "r", "L", "L" } },
|
||||
{ INDEX_op_qemu_ld8s, { "r", "L", "L" } },
|
||||
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
|
||||
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
|
||||
{ INDEX_op_qemu_ld32u, { "r", "L", "L" } },
|
||||
{ INDEX_op_qemu_ld32s, { "r", "L", "L" } },
|
||||
{ INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
|
||||
|
||||
{ INDEX_op_qemu_st8, { "L", "L", "L" } },
|
||||
{ INDEX_op_qemu_st16, { "L", "L", "L" } },
|
||||
{ INDEX_op_qemu_st32, { "L", "L", "L" } },
|
||||
{ INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
|
||||
#endif
|
||||
{ -1 },
|
||||
};
|
||||
|
||||
void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
|
||||
tcg_regset_set32(tcg_target_call_clobber_regs, 0,
|
||||
(1 << TCG_REG_R20) |
|
||||
(1 << TCG_REG_R21) |
|
||||
(1 << TCG_REG_R22) |
|
||||
(1 << TCG_REG_R23) |
|
||||
(1 << TCG_REG_R24) |
|
||||
(1 << TCG_REG_R25) |
|
||||
(1 << TCG_REG_R26));
|
||||
|
||||
tcg_regset_clear(s->reserved_regs);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); /* hardwired to zero */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); /* addil target */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RP); /* link register */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R3); /* frame pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R18); /* return pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */
|
||||
|
||||
tcg_add_target_add_op_defs(hppa_op_defs);
|
||||
}
|
204
tcg/hppa/tcg-target.h
Normal file
204
tcg/hppa/tcg-target.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Tiny Code Generator for QEMU
|
||||
*
|
||||
* Copyright (c) 2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define TCG_TARGET_HPPA 1
|
||||
|
||||
#if defined(_PA_RISC1_1)
|
||||
#define TCG_TARGET_REG_BITS 32
|
||||
#else
|
||||
#error unsupported
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_WORDS_BIGENDIAN
|
||||
|
||||
#define TCG_TARGET_NB_REGS 32
|
||||
|
||||
enum {
|
||||
TCG_REG_R0 = 0,
|
||||
TCG_REG_R1,
|
||||
TCG_REG_RP,
|
||||
TCG_REG_R3,
|
||||
TCG_REG_R4,
|
||||
TCG_REG_R5,
|
||||
TCG_REG_R6,
|
||||
TCG_REG_R7,
|
||||
TCG_REG_R8,
|
||||
TCG_REG_R9,
|
||||
TCG_REG_R10,
|
||||
TCG_REG_R11,
|
||||
TCG_REG_R12,
|
||||
TCG_REG_R13,
|
||||
TCG_REG_R14,
|
||||
TCG_REG_R15,
|
||||
TCG_REG_R16,
|
||||
TCG_REG_R17,
|
||||
TCG_REG_R18,
|
||||
TCG_REG_R19,
|
||||
TCG_REG_R20,
|
||||
TCG_REG_R21,
|
||||
TCG_REG_R22,
|
||||
TCG_REG_R23,
|
||||
TCG_REG_R24,
|
||||
TCG_REG_R25,
|
||||
TCG_REG_R26,
|
||||
TCG_REG_DP,
|
||||
TCG_REG_RET0,
|
||||
TCG_REG_RET1,
|
||||
TCG_REG_SP,
|
||||
TCG_REG_R31,
|
||||
};
|
||||
|
||||
/* used for function call generation */
|
||||
#define TCG_REG_CALL_STACK TCG_REG_SP
|
||||
#define TCG_TARGET_STACK_ALIGN 16
|
||||
#define TCG_TARGET_STACK_GROWSUP
|
||||
|
||||
/* optional instructions */
|
||||
//#define TCG_TARGET_HAS_ext8s_i32
|
||||
//#define TCG_TARGET_HAS_ext16s_i32
|
||||
//#define TCG_TARGET_HAS_bswap16_i32
|
||||
//#define TCG_TARGET_HAS_bswap_i32
|
||||
|
||||
/* Note: must be synced with dyngen-exec.h */
|
||||
#define TCG_AREG0 TCG_REG_R17
|
||||
#define TCG_AREG1 TCG_REG_R14
|
||||
#define TCG_AREG2 TCG_REG_R15
|
||||
#define TCG_AREG3 TCG_REG_R16
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* supplied by libgcc */
|
||||
extern void *__canonicalize_funcptr_for_compare(void *);
|
||||
|
||||
/* 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_12(int as12)
|
||||
{
|
||||
return (((as12 & 0x800) >> 11) |
|
||||
((as12 & 0x400) >> 8) |
|
||||
((as12 & 0x3ff) << 3));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
@ -47,8 +47,9 @@ const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX
|
||||
const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
|
||||
|
||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_target_long value)
|
||||
tcg_target_long value, tcg_target_long addend)
|
||||
{
|
||||
value += addend;
|
||||
switch(type) {
|
||||
case R_386_32:
|
||||
*(uint32_t *)code_ptr = value;
|
||||
|
@ -88,8 +88,9 @@ static const int tcg_target_call_oarg_regs[2] = {
|
||||
};
|
||||
|
||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_target_long value)
|
||||
tcg_target_long value, tcg_target_long addend)
|
||||
{
|
||||
value += addend;
|
||||
switch (type) {
|
||||
case R_SPARC_32:
|
||||
if (value != (uint32_t)value)
|
||||
|
@ -465,10 +465,55 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_NO_DYNGEN_OP
|
||||
|
||||
#if defined __hppa__
|
||||
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_process_stubs(struct hppa_branch_stub *stub,
|
||||
uint8_t **gen_code_pp)
|
||||
{
|
||||
uint32_t *s = (uint32_t *)*gen_code_pp;
|
||||
uint32_t *p = s + 1;
|
||||
|
||||
if (!stub) return;
|
||||
|
||||
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);
|
||||
}
|
||||
/* b,l,n stub,%r0 */
|
||||
*s = 0xe8000002 | reassemble_17((p - s) - 2);
|
||||
*gen_code_pp = (uint8_t *)p;
|
||||
}
|
||||
#endif /* __hppa__ */
|
||||
|
||||
const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr)
|
||||
{
|
||||
uint8_t *gen_code_ptr;
|
||||
|
||||
#ifdef __hppa__
|
||||
struct hppa_branch_stub *hppa_stubs = NULL;
|
||||
#endif
|
||||
|
||||
gen_code_ptr = s->code_ptr;
|
||||
switch(opc) {
|
||||
|
||||
@ -478,6 +523,11 @@ const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr)
|
||||
default:
|
||||
tcg_abort();
|
||||
}
|
||||
|
||||
#ifdef __hppa__
|
||||
hppa_process_stubs(hppa_stubs, &gen_code_ptr);
|
||||
#endif
|
||||
|
||||
s->code_ptr = gen_code_ptr;
|
||||
return opparam_ptr;
|
||||
}
|
||||
|
30
tcg/tcg.c
30
tcg/tcg.c
@ -53,7 +53,7 @@
|
||||
|
||||
|
||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_target_long value);
|
||||
tcg_target_long value, tcg_target_long addend);
|
||||
|
||||
TCGOpDef tcg_op_defs[] = {
|
||||
#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
|
||||
@ -100,7 +100,7 @@ void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
|
||||
/* FIXME: This may break relocations on RISC targets that
|
||||
modify instruction fields in place. The caller may not have
|
||||
written the initial value. */
|
||||
patch_reloc(code_ptr, type, l->u.value + addend);
|
||||
patch_reloc(code_ptr, type, l->u.value, addend);
|
||||
} else {
|
||||
/* add a new relocation entry */
|
||||
r = tcg_malloc(sizeof(TCGRelocation));
|
||||
@ -123,7 +123,7 @@ static void tcg_out_label(TCGContext *s, int label_index,
|
||||
tcg_abort();
|
||||
r = l->u.first_reloc;
|
||||
while (r != NULL) {
|
||||
patch_reloc(r->ptr, r->type, value + r->addend);
|
||||
patch_reloc(r->ptr, r->type, value, r->addend);
|
||||
r = r->next;
|
||||
}
|
||||
l->has_value = 1;
|
||||
@ -1442,7 +1442,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
|
||||
TCGArg arg, func_arg;
|
||||
TCGTemp *ts;
|
||||
tcg_target_long stack_offset, call_stack_size;
|
||||
tcg_target_long stack_offset, call_stack_size, func_addr;
|
||||
int const_func_arg;
|
||||
TCGRegSet allocated_regs;
|
||||
const TCGArgConstraint *arg_ct;
|
||||
@ -1464,7 +1464,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
|
||||
call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) &
|
||||
~(TCG_TARGET_STACK_ALIGN - 1);
|
||||
#ifdef TCG_TARGET_STACK_GROWSUP
|
||||
tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size);
|
||||
#else
|
||||
tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size);
|
||||
#endif
|
||||
|
||||
stack_offset = 0;
|
||||
for(i = nb_regs; i < nb_params; i++) {
|
||||
@ -1487,7 +1491,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
} else {
|
||||
tcg_abort();
|
||||
}
|
||||
#ifdef TCG_TARGET_STACK_GROWSUP
|
||||
stack_offset -= sizeof(tcg_target_long);
|
||||
#else
|
||||
stack_offset += sizeof(tcg_target_long);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* assign input registers */
|
||||
@ -1516,6 +1524,10 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
func_arg = args[nb_oargs + nb_iargs - 1];
|
||||
arg_ct = &def->args_ct[0];
|
||||
ts = &s->temps[func_arg];
|
||||
func_addr = ts->val;
|
||||
#ifdef HOST_HPPA
|
||||
func_addr = (tcg_target_long)__canonicalize_funcptr_for_compare((void *)func_addr);
|
||||
#endif
|
||||
const_func_arg = 0;
|
||||
if (ts->val_type == TEMP_VAL_MEM) {
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
|
||||
@ -1529,12 +1541,12 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
}
|
||||
func_arg = reg;
|
||||
} else if (ts->val_type == TEMP_VAL_CONST) {
|
||||
if (tcg_target_const_match(ts->val, arg_ct)) {
|
||||
if (tcg_target_const_match(func_addr, arg_ct)) {
|
||||
const_func_arg = 1;
|
||||
func_arg = ts->val;
|
||||
func_arg = func_addr;
|
||||
} else {
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
|
||||
tcg_out_movi(s, ts->type, reg, ts->val);
|
||||
tcg_out_movi(s, ts->type, reg, func_addr);
|
||||
func_arg = reg;
|
||||
}
|
||||
} else {
|
||||
@ -1574,7 +1586,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
|
||||
tcg_out_op(s, opc, &func_arg, &const_func_arg);
|
||||
|
||||
#ifdef TCG_TARGET_STACK_GROWSUP
|
||||
tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size);
|
||||
#else
|
||||
tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size);
|
||||
#endif
|
||||
|
||||
/* assign output registers and emit moves if needed */
|
||||
for(i = 0; i < nb_oargs; i++) {
|
||||
|
@ -74,8 +74,9 @@ const int tcg_target_call_oarg_regs[2] = {
|
||||
};
|
||||
|
||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_target_long value)
|
||||
tcg_target_long value, tcg_target_long addend)
|
||||
{
|
||||
value += addend;
|
||||
switch(type) {
|
||||
case R_X86_64_32:
|
||||
if (value != (uint32_t)value)
|
||||
|
Loading…
Reference in New Issue
Block a user