qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] experimental sh4 host support V2


From: Aurelien Jarno
Subject: Re: [Qemu-devel] [PATCH] experimental sh4 host support V2
Date: Wed, 2 Dec 2009 09:36:58 +0100
User-agent: Mutt/1.5.18 (2008-05-17)

On Sun, Nov 15, 2009 at 08:53:55PM +0900, Magnus Damm wrote:
> From: Magnus Damm <address@hidden>
> 
> 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 <address@hidden>
> ---
> 
>  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)
> +{
> +}
> 
> 
> 

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
address@hidden                 http://www.aurel32.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]