Patchwork experimental sh4 host support V2

login
register
mail settings
Submitter Magnus Damm
Date Nov. 15, 2009, 11:53 a.m.
Message ID <20091115115355.9126.25624.sendpatchset@rxone.opensource.se>
Download mbox | patch
Permalink /patch/38448/
State New
Headers show

Comments

Magnus Damm - Nov. 15, 2009, 11:53 a.m.
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.

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(-)
Aurelien Jarno - Dec. 2, 2009, 8:36 a.m.
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)
> +{
> +}
> 
> 
>
Paul Mundt - Dec. 16, 2009, 6:13 a.m.
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?

Patch

--- 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)
+{
+}