[Top][All Lists]
[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
- Re: [Qemu-devel] [PATCH] experimental sh4 host support V2,
Aurelien Jarno <=