Message ID | 20091115115355.9126.25624.sendpatchset@rxone.opensource.se |
---|---|
State | New |
Headers | show |
On Sun, Nov 15, 2009 at 08:53:55PM +0900, Magnus Damm wrote: > From: Magnus Damm <damm@opensource.se> > > This is V2 of the QEMU sh4 host support patch. > > The code is of a somewhat experimental nature, which means that > only the bare essentials are in place. The sh4 host support has > been tested with the sh4 target inside the QEMU sh4 user space > emulator. Only tiny assembly snippets has been tested so far, but > at least syscalls and some branches seem ok at this point. Both > big and little endian hosts are supported, but 64-bit targets and > softmmu are still on the TODO list. The icache handling needs more > work as well. Hi, I have started to review this patch, but I don't know when I'll have time to finish the review. I'll try to do it before the end of the week. Cheers, Aurelien > Signed-off-by: Magnus Damm <damm@opensource.se> > --- > > Changes since V2: > Renamed __function_name() -> tcg_sh4_function_name() > > configure | 11 > cpu-exec.c | 15 > dyngen-exec.h | 4 > exec-all.h | 9 > tcg/sh4/tcg-target.c | 868 ++++++++++++++++++++++++++++++++++++++++++++++++++ > tcg/sh4/tcg-target.h | 65 +++ > 6 files changed, 970 insertions(+), 2 deletions(-) > > --- 0001/configure > +++ work/configure 2009-11-15 20:19:22.000000000 +0900 > @@ -134,13 +134,19 @@ elif check_define _ARCH_PPC ; then > else > cpu="ppc" > fi > +elif check_define __SH4__ ; then > + if check_define __BIG_ENDIAN__ ; then > + cpu="sh4eb" > + else > + cpu="sh4" > + fi > else > cpu=`uname -m` > fi > > target_list="" > case "$cpu" in > - alpha|cris|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|sparc64) > + alpha|cris|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|sh4|sh4eb|sparc64) > cpu="$cpu" > ;; > i386|i486|i586|i686|i86pc|BePC) > @@ -1878,6 +1884,9 @@ case "$cpu" in > armv4b|armv4l) > ARCH=arm > ;; > + sh4|sh4eb) > + ARCH=sh4 > + ;; > *) > echo "Unsupported CPU = $cpu" > exit 1 > --- 0001/cpu-exec.c > +++ work/cpu-exec.c 2009-11-15 20:19:22.000000000 +0900 > @@ -1190,6 +1190,21 @@ int cpu_signal_handler(int host_signum, > &uc->uc_sigmask, puc); > } > > +#elif defined(__SH4__) > + > +int cpu_signal_handler(int host_signum, void *pinfo, > + void *puc) > +{ > + siginfo_t *info = pinfo; > + struct ucontext *uc = puc; > + greg_t pc = uc->uc_mcontext.pc; > + int is_write; > + > + /* XXX: 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 > --- 0001/dyngen-exec.h > +++ work/dyngen-exec.h 2009-11-15 20:19:22.000000000 +0900 > @@ -106,6 +106,10 @@ extern int printf(const char *, ...); > #define AREG0 "r7" > #define AREG1 "r4" > #define AREG2 "r5" > +#elif defined(__SH4__) > +#define AREG0 "r11" > +#define AREG1 "r12" > +#define AREG2 "r13" > #else > #error unsupported CPU > #endif > --- 0001/exec-all.h > +++ work/exec-all.h 2009-11-15 20:19:22.000000000 +0900 > @@ -114,7 +114,7 @@ static inline int tlb_set_page(CPUState > #define CODE_GEN_AVG_BLOCK_SIZE 64 > #endif > > -#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) > +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) || defined(__SH4__) > #define USE_DIRECT_JUMP > #endif > > @@ -189,6 +189,13 @@ extern int code_gen_max_blocks; > #if defined(_ARCH_PPC) > extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); > #define tb_set_jmp_target1 ppc_tb_set_jmp_target > +#elif defined(__SH4__) > +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) > +{ > + /* patch the branch destination */ > + *(uint32_t *)jmp_addr = addr; > + /* FIXME: need to handle caches */ > +} > #elif defined(__i386__) || defined(__x86_64__) > static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) > { > --- /dev/null > +++ work/tcg/sh4/tcg-target.c 2009-11-15 20:33:01.000000000 +0900 > @@ -0,0 +1,868 @@ > +/* > + * Tiny Code Generator for QEMU > + * > + * Copyright (c) 2008 Fabrice Bellard > + * Copyright (c) 2009 Magnus Damm > + * > + * 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. > + */ > + > +#if (defined(TARGET_WORDS_BIGENDIAN) && !defined(HOST_WORDS_BIGENDIAN)) || \ > + (!defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) > +static const int swap_endian = 1; > +#else > +static const int swap_endian = 0; > +#endif > + > +#ifndef CONFIG_USER_ONLY > +#define GUEST_BASE 0 > +#endif > + > +#if TARGET_LONG_BITS != 32 > +#error Only 32-bit targets supported at this point! > +#endif > + > +static uint8_t *tb_ret_addr; > + > +#ifndef NDEBUG > +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { > + "r0", > + "r1", > + "r2", > + "r3", > + "r4", > + "r5", > + "r6", > + "r7", > + "r8", > + "r9", > + "r10", > + "r11", > + "r12", > + "r13", > + "r14", > + "r15", > +}; > +#endif > + > +static const int tcg_target_reg_alloc_order[] = { > + TCG_REG_R8, > + TCG_REG_R9, > + TCG_REG_R10, > + TCG_REG_R11, > + TCG_REG_R12, > + TCG_REG_R13, > + TCG_REG_R0, > + TCG_REG_R1, > + TCG_REG_R2, > + TCG_REG_R3, > + TCG_REG_R4, > + TCG_REG_R5, > + TCG_REG_R6, > + TCG_REG_R7, > +}; > + > +static const int tcg_target_call_iarg_regs[] = { > + TCG_REG_R4, > + TCG_REG_R5, > + TCG_REG_R6, > + TCG_REG_R7, > + TCG_REG_R0, > + TCG_REG_R1, > + TCG_REG_R2, > + TCG_REG_R3, > +}; > + > +static const int tcg_target_call_oarg_regs[2] = { > + TCG_REG_R0, > + TCG_REG_R1, > +}; > + > +static const int tcg_target_callee_save_regs[] = { > + TCG_REG_R1, > + TCG_REG_R2, > + 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, > +}; > + > +#define OPC_ADD 0x300c > +#define OPC_AND 0x2009 > +#define OPC_MULS 0x200f > +#define OPC_NEG 0x600b > +#define OPC_NOP 0x0009 > +#define OPC_OR 0x200b > +#define OPC_RTS 0x000b > +#define OPC_SHAD 0x400c > +#define OPC_SHLD 0x400d > +#define OPC_SUB 0x3008 > +#define OPC_XOR 0x200a > + > +#define OPC_MN(opc, m, n) ((opc) | ((n) << 8) | ((m) << 4)) > +#define OPC_MDN(opc, m, d, n) ((opc) | ((n) << 8) | ((m) << 4) | (d)) > +#define OPC_N(opc, n) ((opc) | (n) << 8) > +#define OPC_NI(opc, n, i) ((opc) | ((n) << 8) | (i)) > +#define OPC_D(opc, d) ((opc) | (d)) > + > +#define ADD(m, n) OPC_MN(OPC_ADD, m, n) /* ADD Rm,Rn */ > +#define AND(m, n) OPC_MN(OPC_AND, m, n) /* AND Rm,Rn */ > +#define BF(d) OPC_D(0x8b00, d) /* BF disp [relative] */ > +#define BT(d) OPC_D(0x8900, d) /* BT disp [relative] */ > +#define BRA(d) OPC_D(0xa000, d) /* BRA disp [relative] */ > +#define CMPEQ(m, n) OPC_MN(0x3000, m, n) /* CMP/EQ Rm,Rn */ > +#define CMPGE(m, n) OPC_MN(0x3003, m, n) /* CMP/GE Rm,Rn */ > +#define CMPGT(m, n) OPC_MN(0x3007, m, n) /* CMP/GT Rm,Rn */ > +#define CMPHI(m, n) OPC_MN(0x3006, m, n) /* CMP/HI Rm,Rn */ > +#define CMPHS(m, n) OPC_MN(0x3002, m, n) /* CMP/HS Rm,Rn */ > +#define EXTSB(m, n) OPC_MN(0x600e, m, n) /* EXTS.B Rm,Rn [sign extend] */ > +#define EXTSW(m, n) OPC_MN(0x600f, m, n) /* EXTS.W Rm,Rn [sign extend] */ > +#define EXTUB(m, n) OPC_MN(0x600c, m, n) /* EXTU.B Rm,Rn [zero extend] */ > +#define EXTUW(m, n) OPC_MN(0x600d, m, n) /* EXTU.W Rm,Rn [zero extend] */ > +#define JMP(n) OPC_N(0x402b, n) /* JMP @Rn */ > +#define JSR(n) OPC_N(0x400b, n) /* JSR @Rn */ > +#define LDSMPR(n) OPC_N(0x4026, n) /* LDS.L @Rm+,PR */ > +#define MOV(m, n) OPC_MN(0x6003, m, n) /* MOV Rm,Rn */ > +#define MOVI(i, n) OPC_NI(0xe000, n, i) /* MOV #imm, Rn */ > +#define MOVWI(d, n) OPC_NI(0x9000, n ,d) /* MOV.W @(disp, PC),Rn */ > +#define MOVLI(d, n) OPC_NI(0xd000, n, d) /* MOV.L @(disp, PC),Rn */ > +#define MOVBS(m, n) OPC_MN(0x2000, m, n) /* MOV.B Rm,@Rn */ > +#define MOVWS(m, n) OPC_MN(0x2001, m, n) /* MOV.W Rm,@Rn */ > +#define MOVLS(m, n) OPC_MN(0x2002, m, n) /* MOV.L Rm,@Rn */ > +#define MOVBL(m, n) OPC_MN(0x6000, m, n) /* MOV.B @Rm,Rn [sign extend] */ > +#define MOVWL(m, n) OPC_MN(0x6001, m, n) /* MOV.W @Rm,Rn [sign extend] */ > +#define MOVLL(m, n) OPC_MN(0x6002, m, n) /* MOV.L @Rm,Rn */ > +#define MOVLM(m, n) OPC_MN(0x2006, m, n) /* MOV.L Rm,@-Rn */ > +#define MOVLP(m, n) OPC_MN(0x6006, m, n) /* MOV.L @Rm+,Rn */ > +#define MOVLS4(m, d, n) OPC_MDN(0x1000, m, d, n) /* MOV.L Rm,@(disp,Rn) */ > +#define MOVLL4(m, d, n) OPC_MDN(0x5000, m, d, n) /* MOV.L @(disp,Rm),Rn */ > +#define MULS(m, n) OPC_MN(OPC_MULS, m, n) /* MULS Rm,Rn */ > +#define NEG(m, n) OPC_MN(OPC_NEG, m, n) /* NEG Rm,Rn */ > +#define OR(m, n) OPC_MN(OPC_OR, m, n) /* OR Rm, Rn */ > +#define SHAD(m, n) OPC_MN(OPC_SHAD, m, n) /* SHAD Rm,Rn */ > +#define SHLD(m, n) OPC_MN(OPC_SHLD, m, n) /* SHLD Rm,Rn */ > +#define SUB(m, n) OPC_MN(OPC_SUB, m, n) /* SUB Rm,Rn */ > +#define SWAPB(m, n) OPC_MN(0x6008, m, n) /* SWAPB Rm,Rn */ > +#define SWAPW(m, n) OPC_MN(0x6009, m, n) /* SWAPW Rm,Rn */ > +#define STS_MACL(n) OPC_N(0x001a, n) /* STS MACL,Rn */ > +#define STSMPR(n) OPC_N(0x4022, n) /* STS.L PR,@-Rn */ > +#define XOR(m, n) OPC_MN(OPC_XOR, m, n) /* XOR Rm,Rn */ > + > +static void tcg_sh4_mov(TCGContext *s, int ret, int arg) > +{ > + tcg_out16(s, MOV(arg, ret)); > +} > + > +static int tcg_sh4_need_pc_align(TCGContext *s) > +{ > + unsigned long pc = (unsigned long)s->code_ptr; > + > + if (pc & 0x01) > + tcg_abort (); > + > + if (pc & 0x02) > + return 1; > + > + return 0; > +} > + > +static uint8_t *tcg_sh4_movi32(TCGContext *s, int ret, tcg_target_long arg, > + unsigned int opc1, unsigned int opc2) > +{ > + uint8_t *reloc_pos; > + int needs_align = tcg_sh4_need_pc_align(s); > + > + tcg_out16(s, MOVLI(1, ret)); > + if (!needs_align || opc2 == OPC_NOP) { > + tcg_out16(s, BRA(3 - needs_align)); > + tcg_out16(s, opc1); /* delay slot */ > + if (!needs_align) > + tcg_out16(s, MOV(0, 0)); /* Never reached */ > + } else { > + tcg_out16(s, opc1); > + tcg_out16(s, BRA(2)); > + tcg_out16(s, opc2); /* delay slot */ > + opc2 = OPC_NOP; > + } > + > + reloc_pos = s->code_ptr; > + tcg_out32(s, arg); /* Must be 32-bit aligned */ > + > + if (opc2 != OPC_NOP) > + tcg_out16(s, opc2); > + > + return reloc_pos; > +} > + > +static void tcg_sh4_movi(TCGContext *s, int ret, tcg_target_long arg, > + unsigned int opc1, unsigned int opc2) > +{ > + do { > + if (arg == (int8_t) arg) { > + tcg_out16(s, MOVI(arg & 0xff, ret)); > + if (opc1 != OPC_NOP) > + tcg_out16(s, opc1); > + break; > + } > + > + if (arg == (uint8_t) arg) { > + tcg_out16(s, MOVI(arg & 0xff, ret)); > + tcg_out16(s, EXTUB(ret, ret)); > + if (opc1 != OPC_NOP) > + tcg_out16(s, opc1); > + break; > + } > + > + if (arg == (int16_t) arg) { > + tcg_out16(s, MOVWI(1, ret)); > + tcg_out16(s, BRA(1)); > + tcg_out16(s, opc1); /* delay slot */ > + tcg_out16(s, arg); > + break; > + } > + > + tcg_sh4_movi32(s, ret, arg, opc1, opc2); > + opc2 = OPC_NOP; > + } while (0); > + > + if (opc2 != OPC_NOP) > + tcg_out16(s, opc2); > +} > + > +static void tcg_sh4_ld(TCGContext *s, int size, int is_signed, > + int ret, int arg1, int offset) > +{ > + unsigned int opc = MOV(0, 0); > + unsigned int tmp; > + > + if (size == 32 && offset > 0 && offset <= 60 && !(offset & 3) ) { > + tcg_out16(s, MOVLL4(arg1, (offset >> 2), ret)); > + return; > + } > + > + if (offset) > + tmp = TCG_REG_R14; > + else > + tmp = arg1; > + > + switch (size) { > + case 8: > + opc = MOVBL(tmp, ret); > + break; > + case 16: > + opc = MOVWL(tmp, ret); > + break; > + case 32: > + opc = MOVLL(tmp, ret); > + break; > + default: > + fprintf(stderr, "unsupported tcg_sh4_ld size\n"); > + tcg_abort(); > + } > + > + if (offset) > + tcg_sh4_movi(s, TCG_REG_R14, offset, ADD(arg1, TCG_REG_R14), opc); > + else > + tcg_out16(s, opc); > + > + if (!is_signed) { > + if (size == 8) > + tcg_out16(s, EXTUB(ret, ret)); > + if (size == 16) > + tcg_out16(s, EXTUW(ret, ret)); > + } > +} > + > +static void tcg_sh4_ld_swap(TCGContext *s, int size, int is_signed, > + int ret, int arg1, int offset) > +{ > + tcg_sh4_ld(s, size, 1, ret, arg1, offset); > + > + if (size == 16) { > + tcg_out16(s, SWAPB(ret, ret)); > + if (is_signed) > + tcg_out16(s, EXTSW(ret, ret)); > + else > + tcg_out16(s, EXTUW(ret, ret)); > + } > + if (size == 32) { > + tcg_out16(s, SWAPB(ret, ret)); > + tcg_out16(s, SWAPW(ret, ret)); > + tcg_out16(s, SWAPB(ret, ret)); > + } > +} > + > +static void tcg_sh4_st(TCGContext *s, int size, int arg, int arg1, int offset) > +{ > + unsigned int opc = MOV(0, 0); > + unsigned int tmp; > + > + if (size == 32 && offset > 0 && !(offset & 3) && offset <= 60) { > + tcg_out16(s, MOVLS4(arg1, (offset >> 2), arg)); > + return; > + } > + > + if (offset) > + tmp = TCG_REG_R14; > + else > + tmp = arg; > + > + switch (size) { > + case 8: > + opc = MOVBS(arg1, tmp); > + break; > + case 16: > + opc = MOVWS(arg1, tmp); > + break; > + case 32: > + opc = MOVLS(arg1, tmp); > + break; > + default: > + fprintf(stderr, "unsupported tcg_sh4_st size\n"); > + tcg_abort(); > + } > + > + if (offset) > + tcg_sh4_movi(s, TCG_REG_R14, offset, ADD(arg, TCG_REG_R14), opc); > + else > + tcg_out16(s, opc); > +} > + > +static void tcg_sh4_st_swap(TCGContext *s, int size, int arg, > + int arg1, int offset) > +{ > + if (offset == 0) { > + if (size == 16) { > + tcg_out16(s, SWAPB(arg1, TCG_REG_R14)); > + tcg_out16(s, MOVWS(TCG_REG_R14, arg)); > + } > + if (size == 32) { > + tcg_out16(s, SWAPB(arg1, TCG_REG_R14)); > + tcg_out16(s, SWAPW(TCG_REG_R14, TCG_REG_R14)); > + tcg_out16(s, SWAPB(TCG_REG_R14, TCG_REG_R14)); > + tcg_out16(s, MOVLS(TCG_REG_R14, arg)); > + } > + } else { > + if (size == 16 || size == 32) > + tcg_out16(s, SWAPB(arg1, arg1)); > + > + if (size == 32) { > + tcg_out16(s, SWAPW(arg1, arg1)); > + tcg_out16(s, SWAPB(arg1, arg1)); > + } > + > + tcg_sh4_st(s, size, arg, arg1, offset); > + > + if (size == 32) { > + tcg_out16(s, SWAPB(arg1, arg1)); > + tcg_out16(s, SWAPW(arg1, arg1)); > + } > + if (size == 16 || size == 32) > + tcg_out16(s, SWAPB(arg1, arg1)); > + } > +} > + > +static void tcg_sh4_alu(TCGContext *s, int ret, unsigned int opc, int arg1, > + tcg_target_long arg2, int const_arg2) > +{ > + int tmp = TCG_REG_R14; > + > + if (const_arg2) { > + if (ret == arg1) > + tcg_sh4_movi(s, tmp, arg2, OPC_MN(opc, tmp, ret), OPC_NOP); > + else > + tcg_sh4_movi(s, tmp, arg2, OPC_MN(opc, arg1, tmp), MOV(tmp, ret)); > + } else { > + if (ret == arg1) > + tcg_out16(s, OPC_MN(opc, arg2, ret)); > + else { > + tcg_out16(s, MOV(arg2, tmp)); > + tcg_out16(s, OPC_MN(opc, arg1, tmp)); > + tcg_out16(s, MOV(tmp, ret)); > + } > + } > +} > + > +static void tcg_sh4_shr(TCGContext *s, int ret, unsigned int opc, > + int arg1, tcg_target_long arg2, int const_arg2) > +{ > + if (const_arg2) > + tcg_sh4_alu(s, ret, opc, arg1, -arg2, 1); > + else { > + if (ret == arg1) { > + tcg_out16(s, NEG(arg2, TCG_REG_R14)); > + tcg_out16(s, OPC_MN(opc, TCG_REG_R14, ret)); > + } else { > + tcg_out16(s, NEG(arg2, TCG_REG_R14)); > + tcg_out16(s, MOV(arg1, ret)); > + tcg_out16(s, OPC_MN(opc, TCG_REG_R14, ret)); > + } > + } > +} > + > +static void tcg_sh4_mul(TCGContext *s, int ret, int arg1, > + tcg_target_long arg2, int const_arg2) > +{ > + int tmp = TCG_REG_R14; > + > + if (const_arg2) > + tcg_sh4_movi(s, tmp, arg2, OPC_MN(OPC_MULS, arg1, tmp), STS_MACL(ret)); > + else { > + tcg_out16(s, OPC_MN(OPC_MULS, arg2, arg1)); > + tcg_out16(s, STS_MACL(ret)); > + } > +} > + > +static unsigned int tcg_sh4_cmp_opc(TCGContext *s, int cond, int arg1, int arg2) > +{ > + unsigned int opc = MOV(0, 0); > + > + switch (cond) { > + case TCG_COND_EQ: > + case TCG_COND_NE: > + opc = CMPEQ(arg1, arg2); > + break; > + case TCG_COND_GT: > + case TCG_COND_LT: > + opc = CMPGT(arg1, arg2); > + break; > + case TCG_COND_GE: > + case TCG_COND_LE: > + opc = CMPGE(arg1, arg2); > + break; > + case TCG_COND_GTU: > + case TCG_COND_LTU: > + opc = CMPHI(arg1, arg2); > + break; > + case TCG_COND_GEU: > + case TCG_COND_LEU: > + opc = CMPHS(arg1, arg2); > + break; > + } > + > + return opc; > +} > + > +static unsigned int tcg_sh4_cmp_inv(TCGContext *s, int cond) > +{ > + switch (cond) { > + case TCG_COND_NE: > + case TCG_COND_LT: > + case TCG_COND_LE: > + case TCG_COND_LTU: > + case TCG_COND_LEU: > + return 1; > + } > + > + return 0; > +} > + > +static void tcg_sh4_jmp_reg(TCGContext *s, int arg) > +{ > + tcg_out16(s, JMP(arg)); > + tcg_out16(s, OPC_NOP); /* delay slot */ > +} > + > +static void tcg_sh4_jmp_imm(TCGContext *s, tcg_target_long arg) > +{ > + tcg_sh4_movi(s, TCG_REG_R14, arg, OPC_NOP, OPC_NOP); > + tcg_sh4_jmp_reg(s, TCG_REG_R14); > +} > + > +static void tcg_sh4_jmp(TCGContext *s, tcg_target_long arg, int const_arg) > +{ > + if (const_arg) > + tcg_sh4_jmp_imm(s, arg); > + else > + tcg_sh4_jmp_reg(s, arg); > +} > + > +static uint8_t *tcg_sh4_jmp_imm32(TCGContext *s, unsigned int opc1, > + unsigned int opc2) > +{ > + uint8_t *reloc_slot; > + > + reloc_slot = tcg_sh4_movi32(s, TCG_REG_R14, 0, opc1, OPC_NOP); > + > + if (opc2 != OPC_NOP) > + tcg_out16(s, opc2); > + > + tcg_sh4_jmp_reg(s, TCG_REG_R14); > + return reloc_slot; > +} > + > +static void tcg_sh4_jmp_index(TCGContext *s, unsigned int opc1, > + unsigned int opc2, int index) > +{ > + tcg_out_reloc(s, tcg_sh4_jmp_imm32(s, opc1, opc2), 0, index, 0); > +} > + > +static void tcg_sh4_brcond(TCGContext *s, int arg0, int arg1, int cond, > + int index) > +{ > + unsigned int opc1 = tcg_sh4_cmp_opc(s, cond, arg0, arg1); > + unsigned int opc2 = tcg_sh4_cmp_inv(s, cond) ? BT(1) : BF(1); > + > + tcg_sh4_jmp_index(s, opc1, opc2, index); > +} > + > +static void tcg_sh4_jsr(TCGContext *s, tcg_target_long arg, int const_arg) > +{ > + if (const_arg) { > + tcg_sh4_movi(s, TCG_REG_R14, arg, STSMPR(TCG_REG_R15), OPC_NOP); > + arg = TCG_REG_R14; > + } > + else > + tcg_out16(s, STSMPR(TCG_REG_R15)); > + > + tcg_out16(s, JSR(arg)); > + tcg_out16(s, OPC_NOP); /* delay slot */ > + tcg_out16(s, LDSMPR(TCG_REG_R15)); > +} > + > +static void tcg_sh4_qemu_ld(TCGContext *s, const TCGArg *args, > + int size, int is_signed) > +{ > + if (size == 8 || !swap_endian) > + tcg_sh4_ld(s, size, is_signed, args[0], args[1], GUEST_BASE); > + else > + tcg_sh4_ld_swap(s, size, is_signed, args[0], args[1], GUEST_BASE); > +} > + > +static void tcg_sh4_qemu_st(TCGContext *s, const TCGArg *args, int size) > +{ > + if (size == 8 || !swap_endian) > + tcg_sh4_st(s, size, args[0], args[1], GUEST_BASE); > + else > + tcg_sh4_st_swap(s, size, args[0], args[1], GUEST_BASE); > +} > + > +static void tcg_out_mov(TCGContext *s, int ret, int arg) > +{ > + tcg_sh4_mov(s, ret, arg); > +} > + > +static void tcg_out_movi(TCGContext *s, TCGType type, > + int ret, tcg_target_long arg) > +{ > + tcg_sh4_movi(s, ret, arg, OPC_NOP, OPC_NOP); > +} > + > +static void tcg_out_ld(TCGContext *s, TCGType type, int ret, int arg1, > + tcg_target_long arg2) > +{ > + tcg_sh4_ld(s, 32, 0, ret, arg1, arg2); > +} > + > +static void tcg_out_st(TCGContext *s, TCGType type, int arg, int arg1, > + tcg_target_long arg2) > +{ > + tcg_sh4_st(s, 32, arg1, arg, arg2); > +} > + > +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) > +{ > + tcg_sh4_alu(s, reg, OPC_ADD, reg, val, 1); > +} > + > +static void patch_reloc(uint8_t *code_ptr, int type, > + tcg_target_long value, tcg_target_long addend) > +{ > + *(uint32_t *)code_ptr = value; > +} > + > +/* maximum number of register used for input function arguments */ > +static int tcg_target_get_call_iarg_regs_count(int flags) > +{ > + return ARRAY_SIZE (tcg_target_call_iarg_regs); > +} > + > +/* parse target specific constraints */ > +static 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, 0x0000ffff); > + break; > + /* qemu_ld/st address constraint */ > + case 'L': > + ct->ct |= TCG_CT_REG; > + tcg_regset_set32(ct->u.regs, 0, 0x0000ffff); > + break; > + default: > + return -1; > + } > + > + ct_str++; > + *pct_str = ct_str; > + return 0; > +} > + > +/* test if a constant matches the constraint */ > +static int tcg_target_const_match(tcg_target_long val, > + const TCGArgConstraint *arg_ct) > +{ > + int ct; > + > + ct = arg_ct->ct; > + if (ct & TCG_CT_CONST) > + return 1; > + return 0; > +} > + > +void tcg_target_qemu_prologue(TCGContext *s) > +{ > + int i, frame_size, push_size, stack_addend; > + > + /* TB prologue */ > + /* save all callee saved registers */ > + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) > + tcg_out16(s, MOVLM(tcg_target_callee_save_regs[i], TCG_REG_R15)); > + > + /* reserve some stack space */ > + push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4; > + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; > + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & > + ~(TCG_TARGET_STACK_ALIGN - 1); > + stack_addend = frame_size - push_size; > + tcg_out_addi(s, TCG_REG_R15, -stack_addend); > + > + tcg_sh4_jmp_reg(s, TCG_REG_R4); /* tb_ptr in R4 from tcg_qemu_tb_exec() */ > + > + /* TB epilogue */ > + tb_ret_addr = s->code_ptr; > + tcg_out_addi(s, TCG_REG_R15, stack_addend); > + > + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) > + tcg_out16(s, MOVLP(TCG_REG_R15, tcg_target_callee_save_regs[i])); > + > + tcg_out16(s, OPC_RTS); > + tcg_out16(s, OPC_NOP); /* delay slot */ > +} > + > +static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, > + const int *const_args) > +{ > + switch (opc) { > + case INDEX_op_exit_tb: > + tcg_sh4_movi(s, TCG_REG_R0, args[0], OPC_NOP, OPC_NOP); > + tcg_sh4_jmp_imm(s, (tcg_target_long) tb_ret_addr); > + break; > + case INDEX_op_goto_tb: > + if (s->tb_jmp_offset) { /* direct jump method */ > + uint8_t *imm32_addr = tcg_sh4_jmp_imm32(s, OPC_NOP, OPC_NOP); > + s->tb_jmp_offset[args[0]] = imm32_addr - s->code_buf; > + } else { > + fprintf(stderr, "unsupported indirect goto_tb\n"); > + tcg_abort(); > + } > + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; > + break; > + case INDEX_op_br: > + tcg_sh4_jmp_index(s, OPC_NOP, OPC_NOP, args[0]); > + break; > + case INDEX_op_call: > + tcg_sh4_jsr(s, args[0], const_args[0]); > + break; > + case INDEX_op_jmp: > + tcg_sh4_jmp(s, args[0], const_args[0]); > + break; > + case INDEX_op_mov_i32: > + tcg_sh4_mov(s, args[0], args[1]); > + break; > + case INDEX_op_movi_i32: > + tcg_sh4_movi(s, args[0], args[1], OPC_NOP, OPC_NOP); > + break; > + case INDEX_op_ld8u_i32: > + tcg_sh4_ld(s, 8, 0, args[0], args[1], args[2]); > + break; > + case INDEX_op_ld8s_i32: > + tcg_sh4_ld(s, 8, 1, args[0], args[1], args[2]); > + break; > + case INDEX_op_ld16u_i32: > + tcg_sh4_ld(s, 16, 0, args[0], args[1], args[2]); > + break; > + case INDEX_op_ld16s_i32: > + tcg_sh4_ld(s, 16, 1, args[0], args[1], args[2]); > + break; > + case INDEX_op_ld_i32: > + tcg_sh4_ld(s, 32, 0, args[0], args[1], args[2]); > + break; > + case INDEX_op_st8_i32: > + tcg_sh4_st(s, 8, args[0], args[1], args[2]); > + break; > + case INDEX_op_st16_i32: > + tcg_sh4_st(s, 16, args[0], args[1], args[2]); > + break; > + case INDEX_op_st_i32: > + tcg_sh4_st(s, 32, args[0], args[1], args[2]); > + break; > + case INDEX_op_add_i32: > + tcg_sh4_alu(s, args[0], OPC_ADD, args[1],args[2], const_args[2]); > + break; > + case INDEX_op_sub_i32: > + tcg_sh4_alu(s, args[0], OPC_SUB, args[1], args[2], 0); > + break; > + case INDEX_op_and_i32: > + tcg_sh4_alu(s, args[0], OPC_AND, args[1], args[2], const_args[2]); > + break; > + case INDEX_op_or_i32: > + tcg_sh4_alu(s, args[0], OPC_OR, args[1], args[2], const_args[2]); > + break; > + case INDEX_op_xor_i32: > + tcg_sh4_alu(s, args[0], OPC_XOR, args[1], args[2], const_args[2]); > + break; > + case INDEX_op_mul_i32: > + tcg_sh4_mul(s, args[0], args[1], args[2], const_args[2]); > + break; > + case INDEX_op_shl_i32: > + tcg_sh4_alu(s, args[0], OPC_SHLD, args[1], args[2], const_args[2]); > + break; > + case INDEX_op_shr_i32: > + tcg_sh4_shr(s, args[0], OPC_SHLD, args[1], args[2], const_args[2]); > + break; > + case INDEX_op_sar_i32: > + tcg_sh4_shr(s, args[0], OPC_SHAD, args[1], args[2], const_args[2]); > + 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: > + tcg_sh4_brcond(s, args[0], args[1], args[2], args[3]); > + break; > + case INDEX_op_qemu_ld8u: > + tcg_sh4_qemu_ld(s, args, 8, 0); > + break; > + case INDEX_op_qemu_ld8s: > + tcg_sh4_qemu_ld(s, args, 8, 1); > + break; > + case INDEX_op_qemu_ld16u: > + tcg_sh4_qemu_ld(s, args, 16, 0); > + break; > + case INDEX_op_qemu_ld16s: > + tcg_sh4_qemu_ld(s, args, 16, 1); > + break; > + case INDEX_op_qemu_ld32u: > + tcg_sh4_qemu_ld(s, args, 32, 0); > + break; > + case INDEX_op_qemu_ld64: > + tcg_sh4_qemu_ld(s, args, 64, 0); > + break; > + case INDEX_op_qemu_st8: > + tcg_sh4_qemu_st(s, args, 8); > + break; > + case INDEX_op_qemu_st16: > + tcg_sh4_qemu_st(s, args, 16); > + break; > + case INDEX_op_qemu_st32: > + tcg_sh4_qemu_st(s, args, 32); > + break; > + case INDEX_op_qemu_st64: > + tcg_sh4_qemu_st(s, args, 64); > + break; > + > + default: > + tcg_dump_ops (s, stderr); > + tcg_abort (); > + } > +} > + > +static const TCGTargetOpDef sh4_op_defs[] = { > + { INDEX_op_exit_tb, { } }, > + { INDEX_op_goto_tb, { } }, > + { INDEX_op_call, { "ri" } }, > + { INDEX_op_jmp, { "ri" } }, > + { 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_sub_i32, { "r", "r", "r" } }, > + { INDEX_op_and_i32, { "r", "r", "ri" } }, > + { INDEX_op_or_i32, { "r", "r", "ri" } }, > + { INDEX_op_xor_i32, { "r", "r", "ri" } }, > + { INDEX_op_add_i32, { "r", "r", "ri" } }, > + { INDEX_op_mul_i32, { "r", "r", "ri" } }, > + > + { INDEX_op_shl_i32, { "r", "r", "ri" } }, > + { INDEX_op_shr_i32, { "r", "r", "ri" } }, > + { INDEX_op_sar_i32, { "r", "r", "ri" } }, > + > + { INDEX_op_brcond_i32, { "r", "r" } }, > + > + { 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_ld32s, { "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" } }, > + > + { -1 }, > +}; > + > +void tcg_target_init(TCGContext *s) > +{ > + /* fail safe */ > + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) > + tcg_abort(); > + > + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0x0000ffff); > + tcg_regset_set32(tcg_target_call_clobber_regs, 0, 0); > + > + tcg_regset_clear(s->reserved_regs); > + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14); /* Scratch */ > + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R15); /* Stack pointer */ > + > + tcg_add_target_add_op_defs(sh4_op_defs); > +} > --- /dev/null > +++ work/tcg/sh4/tcg-target.h 2009-11-15 20:19:23.000000000 +0900 > @@ -0,0 +1,65 @@ > +/* > + * Tiny Code Generator for QEMU > + * > + * Copyright (c) 2008 Fabrice Bellard > + * Copyright (c) 2009 Magnus Damm > + * > + * 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_SH4 1 > + > +#define TCG_TARGET_REG_BITS 32 > +#ifdef __BIG_ENDIAN__ > +#define TCG_TARGET_WORDS_BIGENDIAN > +#endif > +#define TCG_TARGET_NB_REGS 16 > + > +enum { > + TCG_REG_R0 = 0, > + TCG_REG_R1, > + TCG_REG_R2, > + 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, > +}; > + > +/* used for function call generation */ > +#define TCG_REG_CALL_STACK TCG_REG_R15 > +#define TCG_TARGET_STACK_ALIGN 16 > +#define TCG_TARGET_CALL_STACK_OFFSET 0 > + > +#define TCG_AREG0 TCG_REG_R11 > +#define TCG_AREG1 TCG_REG_R12 > +#define TCG_AREG2 TCG_REG_R13 > + > +//#define TCG_TARGET_HAS_GUEST_BASE > + > +static inline void flush_icache_range(unsigned long start, unsigned long stop) > +{ > +} > > >
On Wed, Dec 02, 2009 at 09:36:58AM +0100, Aurelien Jarno wrote: > On Sun, Nov 15, 2009 at 08:53:55PM +0900, Magnus Damm wrote: > > This is V2 of the QEMU sh4 host support patch. > > > > The code is of a somewhat experimental nature, which means that > > only the bare essentials are in place. The sh4 host support has > > been tested with the sh4 target inside the QEMU sh4 user space > > emulator. Only tiny assembly snippets has been tested so far, but > > at least syscalls and some branches seem ok at this point. Both > > big and little endian hosts are supported, but 64-bit targets and > > softmmu are still on the TODO list. The icache handling needs more > > work as well. > > I have started to review this patch, but I don't know when I'll have > time to finish the review. I'll try to do it before the end of the week. > Any updates on this?
--- 0001/configure +++ work/configure 2009-11-15 20:19:22.000000000 +0900 @@ -134,13 +134,19 @@ elif check_define _ARCH_PPC ; then else cpu="ppc" fi +elif check_define __SH4__ ; then + if check_define __BIG_ENDIAN__ ; then + cpu="sh4eb" + else + cpu="sh4" + fi else cpu=`uname -m` fi target_list="" case "$cpu" in - alpha|cris|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|sparc64) + alpha|cris|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|sh4|sh4eb|sparc64) cpu="$cpu" ;; i386|i486|i586|i686|i86pc|BePC) @@ -1878,6 +1884,9 @@ case "$cpu" in armv4b|armv4l) ARCH=arm ;; + sh4|sh4eb) + ARCH=sh4 + ;; *) echo "Unsupported CPU = $cpu" exit 1 --- 0001/cpu-exec.c +++ work/cpu-exec.c 2009-11-15 20:19:22.000000000 +0900 @@ -1190,6 +1190,21 @@ int cpu_signal_handler(int host_signum, &uc->uc_sigmask, puc); } +#elif defined(__SH4__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + greg_t pc = uc->uc_mcontext.pc; + int is_write; + + /* XXX: 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 --- 0001/dyngen-exec.h +++ work/dyngen-exec.h 2009-11-15 20:19:22.000000000 +0900 @@ -106,6 +106,10 @@ extern int printf(const char *, ...); #define AREG0 "r7" #define AREG1 "r4" #define AREG2 "r5" +#elif defined(__SH4__) +#define AREG0 "r11" +#define AREG1 "r12" +#define AREG2 "r13" #else #error unsupported CPU #endif --- 0001/exec-all.h +++ work/exec-all.h 2009-11-15 20:19:22.000000000 +0900 @@ -114,7 +114,7 @@ static inline int tlb_set_page(CPUState #define CODE_GEN_AVG_BLOCK_SIZE 64 #endif -#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) || defined(__SH4__) #define USE_DIRECT_JUMP #endif @@ -189,6 +189,13 @@ extern int code_gen_max_blocks; #if defined(_ARCH_PPC) extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); #define tb_set_jmp_target1 ppc_tb_set_jmp_target +#elif defined(__SH4__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ + /* patch the branch destination */ + *(uint32_t *)jmp_addr = addr; + /* FIXME: need to handle caches */ +} #elif defined(__i386__) || defined(__x86_64__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { --- /dev/null +++ work/tcg/sh4/tcg-target.c 2009-11-15 20:33:01.000000000 +0900 @@ -0,0 +1,868 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * Copyright (c) 2009 Magnus Damm + * + * 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. + */ + +#if (defined(TARGET_WORDS_BIGENDIAN) && !defined(HOST_WORDS_BIGENDIAN)) || \ + (!defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) +static const int swap_endian = 1; +#else +static const int swap_endian = 0; +#endif + +#ifndef CONFIG_USER_ONLY +#define GUEST_BASE 0 +#endif + +#if TARGET_LONG_BITS != 32 +#error Only 32-bit targets supported at this point! +#endif + +static uint8_t *tb_ret_addr; + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", +}; +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_R8, + TCG_REG_R9, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, + TCG_REG_R13, + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, +}; + +static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R4, + TCG_REG_R5, + TCG_REG_R6, + TCG_REG_R7, + TCG_REG_R0, + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, +}; + +static const int tcg_target_call_oarg_regs[2] = { + TCG_REG_R0, + TCG_REG_R1, +}; + +static const int tcg_target_callee_save_regs[] = { + TCG_REG_R1, + TCG_REG_R2, + 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, +}; + +#define OPC_ADD 0x300c +#define OPC_AND 0x2009 +#define OPC_MULS 0x200f +#define OPC_NEG 0x600b +#define OPC_NOP 0x0009 +#define OPC_OR 0x200b +#define OPC_RTS 0x000b +#define OPC_SHAD 0x400c +#define OPC_SHLD 0x400d +#define OPC_SUB 0x3008 +#define OPC_XOR 0x200a + +#define OPC_MN(opc, m, n) ((opc) | ((n) << 8) | ((m) << 4)) +#define OPC_MDN(opc, m, d, n) ((opc) | ((n) << 8) | ((m) << 4) | (d)) +#define OPC_N(opc, n) ((opc) | (n) << 8) +#define OPC_NI(opc, n, i) ((opc) | ((n) << 8) | (i)) +#define OPC_D(opc, d) ((opc) | (d)) + +#define ADD(m, n) OPC_MN(OPC_ADD, m, n) /* ADD Rm,Rn */ +#define AND(m, n) OPC_MN(OPC_AND, m, n) /* AND Rm,Rn */ +#define BF(d) OPC_D(0x8b00, d) /* BF disp [relative] */ +#define BT(d) OPC_D(0x8900, d) /* BT disp [relative] */ +#define BRA(d) OPC_D(0xa000, d) /* BRA disp [relative] */ +#define CMPEQ(m, n) OPC_MN(0x3000, m, n) /* CMP/EQ Rm,Rn */ +#define CMPGE(m, n) OPC_MN(0x3003, m, n) /* CMP/GE Rm,Rn */ +#define CMPGT(m, n) OPC_MN(0x3007, m, n) /* CMP/GT Rm,Rn */ +#define CMPHI(m, n) OPC_MN(0x3006, m, n) /* CMP/HI Rm,Rn */ +#define CMPHS(m, n) OPC_MN(0x3002, m, n) /* CMP/HS Rm,Rn */ +#define EXTSB(m, n) OPC_MN(0x600e, m, n) /* EXTS.B Rm,Rn [sign extend] */ +#define EXTSW(m, n) OPC_MN(0x600f, m, n) /* EXTS.W Rm,Rn [sign extend] */ +#define EXTUB(m, n) OPC_MN(0x600c, m, n) /* EXTU.B Rm,Rn [zero extend] */ +#define EXTUW(m, n) OPC_MN(0x600d, m, n) /* EXTU.W Rm,Rn [zero extend] */ +#define JMP(n) OPC_N(0x402b, n) /* JMP @Rn */ +#define JSR(n) OPC_N(0x400b, n) /* JSR @Rn */ +#define LDSMPR(n) OPC_N(0x4026, n) /* LDS.L @Rm+,PR */ +#define MOV(m, n) OPC_MN(0x6003, m, n) /* MOV Rm,Rn */ +#define MOVI(i, n) OPC_NI(0xe000, n, i) /* MOV #imm, Rn */ +#define MOVWI(d, n) OPC_NI(0x9000, n ,d) /* MOV.W @(disp, PC),Rn */ +#define MOVLI(d, n) OPC_NI(0xd000, n, d) /* MOV.L @(disp, PC),Rn */ +#define MOVBS(m, n) OPC_MN(0x2000, m, n) /* MOV.B Rm,@Rn */ +#define MOVWS(m, n) OPC_MN(0x2001, m, n) /* MOV.W Rm,@Rn */ +#define MOVLS(m, n) OPC_MN(0x2002, m, n) /* MOV.L Rm,@Rn */ +#define MOVBL(m, n) OPC_MN(0x6000, m, n) /* MOV.B @Rm,Rn [sign extend] */ +#define MOVWL(m, n) OPC_MN(0x6001, m, n) /* MOV.W @Rm,Rn [sign extend] */ +#define MOVLL(m, n) OPC_MN(0x6002, m, n) /* MOV.L @Rm,Rn */ +#define MOVLM(m, n) OPC_MN(0x2006, m, n) /* MOV.L Rm,@-Rn */ +#define MOVLP(m, n) OPC_MN(0x6006, m, n) /* MOV.L @Rm+,Rn */ +#define MOVLS4(m, d, n) OPC_MDN(0x1000, m, d, n) /* MOV.L Rm,@(disp,Rn) */ +#define MOVLL4(m, d, n) OPC_MDN(0x5000, m, d, n) /* MOV.L @(disp,Rm),Rn */ +#define MULS(m, n) OPC_MN(OPC_MULS, m, n) /* MULS Rm,Rn */ +#define NEG(m, n) OPC_MN(OPC_NEG, m, n) /* NEG Rm,Rn */ +#define OR(m, n) OPC_MN(OPC_OR, m, n) /* OR Rm, Rn */ +#define SHAD(m, n) OPC_MN(OPC_SHAD, m, n) /* SHAD Rm,Rn */ +#define SHLD(m, n) OPC_MN(OPC_SHLD, m, n) /* SHLD Rm,Rn */ +#define SUB(m, n) OPC_MN(OPC_SUB, m, n) /* SUB Rm,Rn */ +#define SWAPB(m, n) OPC_MN(0x6008, m, n) /* SWAPB Rm,Rn */ +#define SWAPW(m, n) OPC_MN(0x6009, m, n) /* SWAPW Rm,Rn */ +#define STS_MACL(n) OPC_N(0x001a, n) /* STS MACL,Rn */ +#define STSMPR(n) OPC_N(0x4022, n) /* STS.L PR,@-Rn */ +#define XOR(m, n) OPC_MN(OPC_XOR, m, n) /* XOR Rm,Rn */ + +static void tcg_sh4_mov(TCGContext *s, int ret, int arg) +{ + tcg_out16(s, MOV(arg, ret)); +} + +static int tcg_sh4_need_pc_align(TCGContext *s) +{ + unsigned long pc = (unsigned long)s->code_ptr; + + if (pc & 0x01) + tcg_abort (); + + if (pc & 0x02) + return 1; + + return 0; +} + +static uint8_t *tcg_sh4_movi32(TCGContext *s, int ret, tcg_target_long arg, + unsigned int opc1, unsigned int opc2) +{ + uint8_t *reloc_pos; + int needs_align = tcg_sh4_need_pc_align(s); + + tcg_out16(s, MOVLI(1, ret)); + if (!needs_align || opc2 == OPC_NOP) { + tcg_out16(s, BRA(3 - needs_align)); + tcg_out16(s, opc1); /* delay slot */ + if (!needs_align) + tcg_out16(s, MOV(0, 0)); /* Never reached */ + } else { + tcg_out16(s, opc1); + tcg_out16(s, BRA(2)); + tcg_out16(s, opc2); /* delay slot */ + opc2 = OPC_NOP; + } + + reloc_pos = s->code_ptr; + tcg_out32(s, arg); /* Must be 32-bit aligned */ + + if (opc2 != OPC_NOP) + tcg_out16(s, opc2); + + return reloc_pos; +} + +static void tcg_sh4_movi(TCGContext *s, int ret, tcg_target_long arg, + unsigned int opc1, unsigned int opc2) +{ + do { + if (arg == (int8_t) arg) { + tcg_out16(s, MOVI(arg & 0xff, ret)); + if (opc1 != OPC_NOP) + tcg_out16(s, opc1); + break; + } + + if (arg == (uint8_t) arg) { + tcg_out16(s, MOVI(arg & 0xff, ret)); + tcg_out16(s, EXTUB(ret, ret)); + if (opc1 != OPC_NOP) + tcg_out16(s, opc1); + break; + } + + if (arg == (int16_t) arg) { + tcg_out16(s, MOVWI(1, ret)); + tcg_out16(s, BRA(1)); + tcg_out16(s, opc1); /* delay slot */ + tcg_out16(s, arg); + break; + } + + tcg_sh4_movi32(s, ret, arg, opc1, opc2); + opc2 = OPC_NOP; + } while (0); + + if (opc2 != OPC_NOP) + tcg_out16(s, opc2); +} + +static void tcg_sh4_ld(TCGContext *s, int size, int is_signed, + int ret, int arg1, int offset) +{ + unsigned int opc = MOV(0, 0); + unsigned int tmp; + + if (size == 32 && offset > 0 && offset <= 60 && !(offset & 3) ) { + tcg_out16(s, MOVLL4(arg1, (offset >> 2), ret)); + return; + } + + if (offset) + tmp = TCG_REG_R14; + else + tmp = arg1; + + switch (size) { + case 8: + opc = MOVBL(tmp, ret); + break; + case 16: + opc = MOVWL(tmp, ret); + break; + case 32: + opc = MOVLL(tmp, ret); + break; + default: + fprintf(stderr, "unsupported tcg_sh4_ld size\n"); + tcg_abort(); + } + + if (offset) + tcg_sh4_movi(s, TCG_REG_R14, offset, ADD(arg1, TCG_REG_R14), opc); + else + tcg_out16(s, opc); + + if (!is_signed) { + if (size == 8) + tcg_out16(s, EXTUB(ret, ret)); + if (size == 16) + tcg_out16(s, EXTUW(ret, ret)); + } +} + +static void tcg_sh4_ld_swap(TCGContext *s, int size, int is_signed, + int ret, int arg1, int offset) +{ + tcg_sh4_ld(s, size, 1, ret, arg1, offset); + + if (size == 16) { + tcg_out16(s, SWAPB(ret, ret)); + if (is_signed) + tcg_out16(s, EXTSW(ret, ret)); + else + tcg_out16(s, EXTUW(ret, ret)); + } + if (size == 32) { + tcg_out16(s, SWAPB(ret, ret)); + tcg_out16(s, SWAPW(ret, ret)); + tcg_out16(s, SWAPB(ret, ret)); + } +} + +static void tcg_sh4_st(TCGContext *s, int size, int arg, int arg1, int offset) +{ + unsigned int opc = MOV(0, 0); + unsigned int tmp; + + if (size == 32 && offset > 0 && !(offset & 3) && offset <= 60) { + tcg_out16(s, MOVLS4(arg1, (offset >> 2), arg)); + return; + } + + if (offset) + tmp = TCG_REG_R14; + else + tmp = arg; + + switch (size) { + case 8: + opc = MOVBS(arg1, tmp); + break; + case 16: + opc = MOVWS(arg1, tmp); + break; + case 32: + opc = MOVLS(arg1, tmp); + break; + default: + fprintf(stderr, "unsupported tcg_sh4_st size\n"); + tcg_abort(); + } + + if (offset) + tcg_sh4_movi(s, TCG_REG_R14, offset, ADD(arg, TCG_REG_R14), opc); + else + tcg_out16(s, opc); +} + +static void tcg_sh4_st_swap(TCGContext *s, int size, int arg, + int arg1, int offset) +{ + if (offset == 0) { + if (size == 16) { + tcg_out16(s, SWAPB(arg1, TCG_REG_R14)); + tcg_out16(s, MOVWS(TCG_REG_R14, arg)); + } + if (size == 32) { + tcg_out16(s, SWAPB(arg1, TCG_REG_R14)); + tcg_out16(s, SWAPW(TCG_REG_R14, TCG_REG_R14)); + tcg_out16(s, SWAPB(TCG_REG_R14, TCG_REG_R14)); + tcg_out16(s, MOVLS(TCG_REG_R14, arg)); + } + } else { + if (size == 16 || size == 32) + tcg_out16(s, SWAPB(arg1, arg1)); + + if (size == 32) { + tcg_out16(s, SWAPW(arg1, arg1)); + tcg_out16(s, SWAPB(arg1, arg1)); + } + + tcg_sh4_st(s, size, arg, arg1, offset); + + if (size == 32) { + tcg_out16(s, SWAPB(arg1, arg1)); + tcg_out16(s, SWAPW(arg1, arg1)); + } + if (size == 16 || size == 32) + tcg_out16(s, SWAPB(arg1, arg1)); + } +} + +static void tcg_sh4_alu(TCGContext *s, int ret, unsigned int opc, int arg1, + tcg_target_long arg2, int const_arg2) +{ + int tmp = TCG_REG_R14; + + if (const_arg2) { + if (ret == arg1) + tcg_sh4_movi(s, tmp, arg2, OPC_MN(opc, tmp, ret), OPC_NOP); + else + tcg_sh4_movi(s, tmp, arg2, OPC_MN(opc, arg1, tmp), MOV(tmp, ret)); + } else { + if (ret == arg1) + tcg_out16(s, OPC_MN(opc, arg2, ret)); + else { + tcg_out16(s, MOV(arg2, tmp)); + tcg_out16(s, OPC_MN(opc, arg1, tmp)); + tcg_out16(s, MOV(tmp, ret)); + } + } +} + +static void tcg_sh4_shr(TCGContext *s, int ret, unsigned int opc, + int arg1, tcg_target_long arg2, int const_arg2) +{ + if (const_arg2) + tcg_sh4_alu(s, ret, opc, arg1, -arg2, 1); + else { + if (ret == arg1) { + tcg_out16(s, NEG(arg2, TCG_REG_R14)); + tcg_out16(s, OPC_MN(opc, TCG_REG_R14, ret)); + } else { + tcg_out16(s, NEG(arg2, TCG_REG_R14)); + tcg_out16(s, MOV(arg1, ret)); + tcg_out16(s, OPC_MN(opc, TCG_REG_R14, ret)); + } + } +} + +static void tcg_sh4_mul(TCGContext *s, int ret, int arg1, + tcg_target_long arg2, int const_arg2) +{ + int tmp = TCG_REG_R14; + + if (const_arg2) + tcg_sh4_movi(s, tmp, arg2, OPC_MN(OPC_MULS, arg1, tmp), STS_MACL(ret)); + else { + tcg_out16(s, OPC_MN(OPC_MULS, arg2, arg1)); + tcg_out16(s, STS_MACL(ret)); + } +} + +static unsigned int tcg_sh4_cmp_opc(TCGContext *s, int cond, int arg1, int arg2) +{ + unsigned int opc = MOV(0, 0); + + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + opc = CMPEQ(arg1, arg2); + break; + case TCG_COND_GT: + case TCG_COND_LT: + opc = CMPGT(arg1, arg2); + break; + case TCG_COND_GE: + case TCG_COND_LE: + opc = CMPGE(arg1, arg2); + break; + case TCG_COND_GTU: + case TCG_COND_LTU: + opc = CMPHI(arg1, arg2); + break; + case TCG_COND_GEU: + case TCG_COND_LEU: + opc = CMPHS(arg1, arg2); + break; + } + + return opc; +} + +static unsigned int tcg_sh4_cmp_inv(TCGContext *s, int cond) +{ + switch (cond) { + case TCG_COND_NE: + case TCG_COND_LT: + case TCG_COND_LE: + case TCG_COND_LTU: + case TCG_COND_LEU: + return 1; + } + + return 0; +} + +static void tcg_sh4_jmp_reg(TCGContext *s, int arg) +{ + tcg_out16(s, JMP(arg)); + tcg_out16(s, OPC_NOP); /* delay slot */ +} + +static void tcg_sh4_jmp_imm(TCGContext *s, tcg_target_long arg) +{ + tcg_sh4_movi(s, TCG_REG_R14, arg, OPC_NOP, OPC_NOP); + tcg_sh4_jmp_reg(s, TCG_REG_R14); +} + +static void tcg_sh4_jmp(TCGContext *s, tcg_target_long arg, int const_arg) +{ + if (const_arg) + tcg_sh4_jmp_imm(s, arg); + else + tcg_sh4_jmp_reg(s, arg); +} + +static uint8_t *tcg_sh4_jmp_imm32(TCGContext *s, unsigned int opc1, + unsigned int opc2) +{ + uint8_t *reloc_slot; + + reloc_slot = tcg_sh4_movi32(s, TCG_REG_R14, 0, opc1, OPC_NOP); + + if (opc2 != OPC_NOP) + tcg_out16(s, opc2); + + tcg_sh4_jmp_reg(s, TCG_REG_R14); + return reloc_slot; +} + +static void tcg_sh4_jmp_index(TCGContext *s, unsigned int opc1, + unsigned int opc2, int index) +{ + tcg_out_reloc(s, tcg_sh4_jmp_imm32(s, opc1, opc2), 0, index, 0); +} + +static void tcg_sh4_brcond(TCGContext *s, int arg0, int arg1, int cond, + int index) +{ + unsigned int opc1 = tcg_sh4_cmp_opc(s, cond, arg0, arg1); + unsigned int opc2 = tcg_sh4_cmp_inv(s, cond) ? BT(1) : BF(1); + + tcg_sh4_jmp_index(s, opc1, opc2, index); +} + +static void tcg_sh4_jsr(TCGContext *s, tcg_target_long arg, int const_arg) +{ + if (const_arg) { + tcg_sh4_movi(s, TCG_REG_R14, arg, STSMPR(TCG_REG_R15), OPC_NOP); + arg = TCG_REG_R14; + } + else + tcg_out16(s, STSMPR(TCG_REG_R15)); + + tcg_out16(s, JSR(arg)); + tcg_out16(s, OPC_NOP); /* delay slot */ + tcg_out16(s, LDSMPR(TCG_REG_R15)); +} + +static void tcg_sh4_qemu_ld(TCGContext *s, const TCGArg *args, + int size, int is_signed) +{ + if (size == 8 || !swap_endian) + tcg_sh4_ld(s, size, is_signed, args[0], args[1], GUEST_BASE); + else + tcg_sh4_ld_swap(s, size, is_signed, args[0], args[1], GUEST_BASE); +} + +static void tcg_sh4_qemu_st(TCGContext *s, const TCGArg *args, int size) +{ + if (size == 8 || !swap_endian) + tcg_sh4_st(s, size, args[0], args[1], GUEST_BASE); + else + tcg_sh4_st_swap(s, size, args[0], args[1], GUEST_BASE); +} + +static void tcg_out_mov(TCGContext *s, int ret, int arg) +{ + tcg_sh4_mov(s, ret, arg); +} + +static void tcg_out_movi(TCGContext *s, TCGType type, + int ret, tcg_target_long arg) +{ + tcg_sh4_movi(s, ret, arg, OPC_NOP, OPC_NOP); +} + +static void tcg_out_ld(TCGContext *s, TCGType type, int ret, int arg1, + tcg_target_long arg2) +{ + tcg_sh4_ld(s, 32, 0, ret, arg1, arg2); +} + +static void tcg_out_st(TCGContext *s, TCGType type, int arg, int arg1, + tcg_target_long arg2) +{ + tcg_sh4_st(s, 32, arg1, arg, arg2); +} + +static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) +{ + tcg_sh4_alu(s, reg, OPC_ADD, reg, val, 1); +} + +static void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + *(uint32_t *)code_ptr = value; +} + +/* maximum number of register used for input function arguments */ +static int tcg_target_get_call_iarg_regs_count(int flags) +{ + return ARRAY_SIZE (tcg_target_call_iarg_regs); +} + +/* parse target specific constraints */ +static 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, 0x0000ffff); + break; + /* qemu_ld/st address constraint */ + case 'L': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0x0000ffff); + break; + default: + return -1; + } + + ct_str++; + *pct_str = ct_str; + return 0; +} + +/* test if a constant matches the constraint */ +static int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct; + + ct = arg_ct->ct; + if (ct & TCG_CT_CONST) + return 1; + return 0; +} + +void tcg_target_qemu_prologue(TCGContext *s) +{ + int i, frame_size, push_size, stack_addend; + + /* TB prologue */ + /* save all callee saved registers */ + for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) + tcg_out16(s, MOVLM(tcg_target_callee_save_regs[i], TCG_REG_R15)); + + /* reserve some stack space */ + push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & + ~(TCG_TARGET_STACK_ALIGN - 1); + stack_addend = frame_size - push_size; + tcg_out_addi(s, TCG_REG_R15, -stack_addend); + + tcg_sh4_jmp_reg(s, TCG_REG_R4); /* tb_ptr in R4 from tcg_qemu_tb_exec() */ + + /* TB epilogue */ + tb_ret_addr = s->code_ptr; + tcg_out_addi(s, TCG_REG_R15, stack_addend); + + for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) + tcg_out16(s, MOVLP(TCG_REG_R15, tcg_target_callee_save_regs[i])); + + tcg_out16(s, OPC_RTS); + tcg_out16(s, OPC_NOP); /* delay slot */ +} + +static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, + const int *const_args) +{ + switch (opc) { + case INDEX_op_exit_tb: + tcg_sh4_movi(s, TCG_REG_R0, args[0], OPC_NOP, OPC_NOP); + tcg_sh4_jmp_imm(s, (tcg_target_long) tb_ret_addr); + break; + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { /* direct jump method */ + uint8_t *imm32_addr = tcg_sh4_jmp_imm32(s, OPC_NOP, OPC_NOP); + s->tb_jmp_offset[args[0]] = imm32_addr - s->code_buf; + } else { + fprintf(stderr, "unsupported indirect goto_tb\n"); + tcg_abort(); + } + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_br: + tcg_sh4_jmp_index(s, OPC_NOP, OPC_NOP, args[0]); + break; + case INDEX_op_call: + tcg_sh4_jsr(s, args[0], const_args[0]); + break; + case INDEX_op_jmp: + tcg_sh4_jmp(s, args[0], const_args[0]); + break; + case INDEX_op_mov_i32: + tcg_sh4_mov(s, args[0], args[1]); + break; + case INDEX_op_movi_i32: + tcg_sh4_movi(s, args[0], args[1], OPC_NOP, OPC_NOP); + break; + case INDEX_op_ld8u_i32: + tcg_sh4_ld(s, 8, 0, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i32: + tcg_sh4_ld(s, 8, 1, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i32: + tcg_sh4_ld(s, 16, 0, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i32: + tcg_sh4_ld(s, 16, 1, args[0], args[1], args[2]); + break; + case INDEX_op_ld_i32: + tcg_sh4_ld(s, 32, 0, args[0], args[1], args[2]); + break; + case INDEX_op_st8_i32: + tcg_sh4_st(s, 8, args[0], args[1], args[2]); + break; + case INDEX_op_st16_i32: + tcg_sh4_st(s, 16, args[0], args[1], args[2]); + break; + case INDEX_op_st_i32: + tcg_sh4_st(s, 32, args[0], args[1], args[2]); + break; + case INDEX_op_add_i32: + tcg_sh4_alu(s, args[0], OPC_ADD, args[1],args[2], const_args[2]); + break; + case INDEX_op_sub_i32: + tcg_sh4_alu(s, args[0], OPC_SUB, args[1], args[2], 0); + break; + case INDEX_op_and_i32: + tcg_sh4_alu(s, args[0], OPC_AND, args[1], args[2], const_args[2]); + break; + case INDEX_op_or_i32: + tcg_sh4_alu(s, args[0], OPC_OR, args[1], args[2], const_args[2]); + break; + case INDEX_op_xor_i32: + tcg_sh4_alu(s, args[0], OPC_XOR, args[1], args[2], const_args[2]); + break; + case INDEX_op_mul_i32: + tcg_sh4_mul(s, args[0], args[1], args[2], const_args[2]); + break; + case INDEX_op_shl_i32: + tcg_sh4_alu(s, args[0], OPC_SHLD, args[1], args[2], const_args[2]); + break; + case INDEX_op_shr_i32: + tcg_sh4_shr(s, args[0], OPC_SHLD, args[1], args[2], const_args[2]); + break; + case INDEX_op_sar_i32: + tcg_sh4_shr(s, args[0], OPC_SHAD, args[1], args[2], const_args[2]); + 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: + tcg_sh4_brcond(s, args[0], args[1], args[2], args[3]); + break; + case INDEX_op_qemu_ld8u: + tcg_sh4_qemu_ld(s, args, 8, 0); + break; + case INDEX_op_qemu_ld8s: + tcg_sh4_qemu_ld(s, args, 8, 1); + break; + case INDEX_op_qemu_ld16u: + tcg_sh4_qemu_ld(s, args, 16, 0); + break; + case INDEX_op_qemu_ld16s: + tcg_sh4_qemu_ld(s, args, 16, 1); + break; + case INDEX_op_qemu_ld32u: + tcg_sh4_qemu_ld(s, args, 32, 0); + break; + case INDEX_op_qemu_ld64: + tcg_sh4_qemu_ld(s, args, 64, 0); + break; + case INDEX_op_qemu_st8: + tcg_sh4_qemu_st(s, args, 8); + break; + case INDEX_op_qemu_st16: + tcg_sh4_qemu_st(s, args, 16); + break; + case INDEX_op_qemu_st32: + tcg_sh4_qemu_st(s, args, 32); + break; + case INDEX_op_qemu_st64: + tcg_sh4_qemu_st(s, args, 64); + break; + + default: + tcg_dump_ops (s, stderr); + tcg_abort (); + } +} + +static const TCGTargetOpDef sh4_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, + { 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_sub_i32, { "r", "r", "r" } }, + { INDEX_op_and_i32, { "r", "r", "ri" } }, + { INDEX_op_or_i32, { "r", "r", "ri" } }, + { INDEX_op_xor_i32, { "r", "r", "ri" } }, + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_mul_i32, { "r", "r", "ri" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + + { 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_ld32s, { "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" } }, + + { -1 }, +}; + +void tcg_target_init(TCGContext *s) +{ + /* fail safe */ + if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) + tcg_abort(); + + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0x0000ffff); + tcg_regset_set32(tcg_target_call_clobber_regs, 0, 0); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14); /* Scratch */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_R15); /* Stack pointer */ + + tcg_add_target_add_op_defs(sh4_op_defs); +} --- /dev/null +++ work/tcg/sh4/tcg-target.h 2009-11-15 20:19:23.000000000 +0900 @@ -0,0 +1,65 @@ +/* + * Tiny Code Generator for QEMU + * + * Copyright (c) 2008 Fabrice Bellard + * Copyright (c) 2009 Magnus Damm + * + * 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_SH4 1 + +#define TCG_TARGET_REG_BITS 32 +#ifdef __BIG_ENDIAN__ +#define TCG_TARGET_WORDS_BIGENDIAN +#endif +#define TCG_TARGET_NB_REGS 16 + +enum { + TCG_REG_R0 = 0, + TCG_REG_R1, + TCG_REG_R2, + 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, +}; + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_R15 +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +#define TCG_AREG0 TCG_REG_R11 +#define TCG_AREG1 TCG_REG_R12 +#define TCG_AREG2 TCG_REG_R13 + +//#define TCG_TARGET_HAS_GUEST_BASE + +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +}