--- trunk/src/cpus/cpu_arm_instr.c 2007/10/08 16:19:28 21 +++ trunk/src/cpus/cpu_arm_instr.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_arm_instr.c,v 1.54 2005/11/19 18:53:07 debug Exp $ + * $Id: cpu_arm_instr.c,v 1.60 2006/02/09 22:40:27 debug Exp $ * * ARM instructions. * @@ -36,8 +36,6 @@ */ -#include "arm_quick_pc_to_pointers.h" - /* #define GATHER_BDT_STATISTICS */ @@ -587,6 +585,39 @@ /* + * smulXY: 16-bit * 16-bit multiplication (32-bit result) + * + * arg[0] = ptr to rm + * arg[1] = ptr to rs + * arg[2] = ptr to rd + */ +X(smulbb) +{ + reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) * + (int32_t)(int16_t)reg(ic->arg[1]); +} +Y(smulbb) +X(smultb) +{ + reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) * + (int32_t)(int16_t)reg(ic->arg[1]); +} +Y(smultb) +X(smulbt) +{ + reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) * + (int32_t)(int16_t)(reg(ic->arg[1]) >> 16); +} +Y(smulbt) +X(smultt) +{ + reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) * + (int32_t)(int16_t)(reg(ic->arg[1]) >> 16); +} +Y(smultt) + + +/* * mov_reg_reg: Move a register to another. * * arg[0] = ptr to source register @@ -1991,12 +2022,12 @@ /* - * arm_combine_netbsd_memset(): + * Combine: netbsd_memset(): * * Check for the core of a NetBSD/arm memset; large memsets use a sequence * of 16 store-multiple instructions, each storing 2 registers at a time. */ -void arm_combine_netbsd_memset(struct cpu *cpu, +void COMBINE(netbsd_memset)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN @@ -2021,13 +2052,13 @@ /* - * arm_combine_netbsd_memcpy(): + * Combine: netbsd_memcpy(): * * Check for the core of a NetBSD/arm memcpy; large memcpys use a * sequence of ldmia instructions. */ -void arm_combine_netbsd_memcpy(struct cpu *cpu, - struct arm_instr_call *ic, int low_addr) +void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic, + int low_addr) { #ifdef HOST_LITTLE_ENDIAN int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2051,11 +2082,11 @@ /* - * arm_combine_netbsd_cacheclean(): + * Combine: netbsd_cacheclean(): * * Check for the core of a NetBSD/arm cache clean. (There are two variants.) */ -void arm_combine_netbsd_cacheclean(struct cpu *cpu, +void COMBINE(netbsd_cacheclean)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2075,11 +2106,11 @@ /* - * arm_combine_netbsd_cacheclean2(): + * Combine: netbsd_cacheclean2(): * * Check for the core of a NetBSD/arm cache clean. (Second variant.) */ -void arm_combine_netbsd_cacheclean2(struct cpu *cpu, +void COMBINE(netbsd_cacheclean2)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2100,9 +2131,9 @@ /* - * arm_combine_netbsd_scanc(): + * Combine: netbsd_scanc(): */ -void arm_combine_netbsd_scanc(struct cpu *cpu, +void COMBINE(netbsd_scanc)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2126,9 +2157,9 @@ /* - * arm_combine_strlen(): + * Combine: strlen(): */ -void arm_combine_strlen(struct cpu *cpu, +void COMBINE(strlen)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2150,9 +2181,9 @@ /* - * arm_combine_xchg(): + * Combine: xchg(): */ -void arm_combine_xchg(struct cpu *cpu, +void COMBINE(xchg)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2176,9 +2207,9 @@ /* - * arm_combine_netbsd_copyin(): + * Combine: netbsd_copyin(): */ -void arm_combine_netbsd_copyin(struct cpu *cpu, +void COMBINE(netbsd_copyin)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN @@ -2208,9 +2239,9 @@ /* - * arm_combine_netbsd_copyout(): + * Combine: netbsd_copyout(): */ -void arm_combine_netbsd_copyout(struct cpu *cpu, +void COMBINE(netbsd_copyout)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN @@ -2240,9 +2271,9 @@ /* - * arm_combine_cmps_b(): + * Combine: cmps_b(): */ -void arm_combine_cmps_b(struct cpu *cpu, +void COMBINE(cmps_b)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) @@ -2424,6 +2455,9 @@ X(to_be_translated) { uint32_t addr, low_pc, iword, imm = 0; +#ifdef DYNTRANS_BACKEND + int simple = 0; +#endif unsigned char *page; unsigned char ib[4]; int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8; @@ -2584,8 +2618,17 @@ goto bad; } if ((iword & 0x0ff0f090) == 0x01600080) { - /* TODO: smulXY */ - goto bad; + /* smulXY (16-bit * 16-bit => 32-bit) */ + switch (iword & 0x60) { + case 0x00: ic->f = cond_instr(smulbb); break; + case 0x20: ic->f = cond_instr(smultb); break; + case 0x40: ic->f = cond_instr(smulbt); break; + default: ic->f = cond_instr(smultt); break; + } + ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]); + ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]); + ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /* Rd */ + break; } if ((iword & 0x0ff0f0b0) == 0x012000a0) { /* TODO: smulwY */ @@ -2702,12 +2745,18 @@ /* "mov reg,#0": */ if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) { arm_switch_clear(ic, rd, condition_code); +#ifdef DYNTRANS_BACKEND +simple = 1; +#endif break; } /* "mov reg,#1": */ if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) { arm_switch_mov1(ic, rd, condition_code); +#ifdef DYNTRANS_BACKEND +simple = 1; +#endif break; } @@ -2715,6 +2764,9 @@ if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC && rn == rd) { arm_switch_add1(ic, rd, condition_code); +#ifdef DYNTRANS_BACKEND +simple = 1; +#endif break; } @@ -2767,10 +2819,9 @@ (any_pc_reg? 512 : 0) + (regform? 1024 : 0)]; if (ic->f == instr(eor_regshort)) - cpu->cd.arm.combination_check = arm_combine_xchg; + cpu->cd.arm.combination_check = COMBINE(xchg); if (iword == 0xe113000c) - cpu->cd.arm.combination_check = - arm_combine_netbsd_scanc; + cpu->cd.arm.combination_check = COMBINE(netbsd_scanc); break; case 0x4: /* Load and store... */ @@ -2842,11 +2893,9 @@ } } if (iword == 0xe4b09004) - cpu->cd.arm.combination_check = - arm_combine_netbsd_copyin; + cpu->cd.arm.combination_check = COMBINE(netbsd_copyin); if (iword == 0xe4a17004) - cpu->cd.arm.combination_check = - arm_combine_netbsd_copyout; + cpu->cd.arm.combination_check = COMBINE(netbsd_copyout); break; case 0x8: /* Multiple load/store... (Block data transfer) */ @@ -2899,10 +2948,10 @@ samepage_function = cond_instr(b_samepage); if (iword == 0xcaffffed) cpu->cd.arm.combination_check = - arm_combine_netbsd_memset; + COMBINE(netbsd_memset); if (iword == 0xaafffff9) cpu->cd.arm.combination_check = - arm_combine_netbsd_memcpy; + COMBINE(netbsd_memcpy); } else { if (cpu->machine->show_trace_tree) { ic->f = cond_instr(bl_trace); @@ -2961,15 +3010,15 @@ if (main_opcode == 0xa && (condition_code <= 1 || condition_code == 3 || condition_code == 8 || condition_code == 12 || condition_code == 13)) - cpu->cd.arm.combination_check = arm_combine_cmps_b; + cpu->cd.arm.combination_check = COMBINE(cmps_b); if (iword == 0x1afffffc) - cpu->cd.arm.combination_check = arm_combine_strlen; + cpu->cd.arm.combination_check = COMBINE(strlen); /* Hm. Does this really increase performance? */ if (iword == 0x8afffffa) cpu->cd.arm.combination_check = - arm_combine_netbsd_cacheclean2; + COMBINE(netbsd_cacheclean2); break; case 0xc: @@ -2978,6 +3027,13 @@ * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm */ + if ((iword & 0x0fe00fff) == 0x0c400000) { + /* Special case: mar/mra DSP instructions */ + fatal("TODO: mar/mra DSP instructions!\n"); + /* Perhaps these are actually identical to MCRR/MRRC */ + goto bad; + } + if ((iword & 0x0fe00000) == 0x0c400000) { fatal("MCRR/MRRC: TODO\n"); goto bad; @@ -2989,11 +3045,22 @@ * For now, treat as Undefined instructions. This causes e.g. * Linux/ARM to emulate these instructions (floating point). */ +#if 0 ic->f = cond_instr(und); ic->arg[0] = addr & 0xfff; +#else + fatal("LDC/STC: TODO\n"); + goto bad; +#endif break; case 0xe: + if ((iword & 0x0ff00ff0) == 0x0e200010) { + /* Special case: mia* DSP instructions */ + /* See Intel's 27343601.pdf, page 16-20 */ + fatal("TODO: mia* DSP instructions!\n"); + goto bad; + } if (iword & 0x10) { /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */ ic->arg[0] = iword; @@ -3005,7 +3072,7 @@ } if (iword == 0xee070f9a) cpu->cd.arm.combination_check = - arm_combine_netbsd_cacheclean; + COMBINE(netbsd_cacheclean); break; case 0xf: