1 |
/* |
/* |
2 |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_arm_instr.c,v 1.69 2006/09/09 09:04:32 debug Exp $ |
* $Id: cpu_arm_instr.c,v 1.77 2007/06/28 13:36:46 debug Exp $ |
29 |
* |
* |
30 |
* ARM instructions. |
* ARM instructions. |
31 |
* |
* |
235 |
/* |
/* |
236 |
* b: Branch (to a different translated page) |
* b: Branch (to a different translated page) |
237 |
* |
* |
238 |
* arg[0] = relative offset |
* arg[0] = relative offset from start of page |
239 |
*/ |
*/ |
240 |
X(b) |
X(b) |
241 |
{ |
{ |
989 |
X(store_w0_byte_u1_p0_imm); |
X(store_w0_byte_u1_p0_imm); |
990 |
X(store_w0_word_u1_p0_imm); |
X(store_w0_word_u1_p0_imm); |
991 |
X(store_w0_word_u1_p1_imm); |
X(store_w0_word_u1_p1_imm); |
|
X(load_w1_word_u1_p0_imm); |
|
992 |
X(load_w0_word_u1_p0_imm); |
X(load_w0_word_u1_p0_imm); |
993 |
|
X(load_w0_word_u1_p1_imm); |
994 |
|
X(load_w1_word_u1_p0_imm); |
995 |
X(load_w0_byte_u1_p1_imm); |
X(load_w0_byte_u1_p1_imm); |
996 |
X(load_w0_byte_u1_p1_reg); |
X(load_w0_byte_u1_p1_reg); |
997 |
X(load_w1_byte_u1_p1_imm); |
X(load_w1_byte_u1_p1_imm); |
1535 |
|
|
1536 |
|
|
1537 |
/* |
/* |
1538 |
|
* netbsd_idle: |
1539 |
|
* |
1540 |
|
* L: ldr rX,[rY] |
1541 |
|
* teqs rX,#0 |
1542 |
|
* bne X (samepage) |
1543 |
|
* teqs rZ,#0 |
1544 |
|
* beq L (samepage) |
1545 |
|
* .... |
1546 |
|
* X: somewhere else on the same page |
1547 |
|
*/ |
1548 |
|
X(netbsd_idle) |
1549 |
|
{ |
1550 |
|
uint32_t rY = reg(ic[0].arg[0]); |
1551 |
|
uint32_t rZ = reg(ic[3].arg[0]); |
1552 |
|
uint32_t *p; |
1553 |
|
uint32_t rX; |
1554 |
|
|
1555 |
|
p = (uint32_t *) cpu->cd.arm.host_load[rY >> 12]; |
1556 |
|
if (p == NULL) { |
1557 |
|
instr(load_w0_word_u1_p1_imm)(cpu, ic); |
1558 |
|
return; |
1559 |
|
} |
1560 |
|
|
1561 |
|
rX = p[(rY & 0xfff) >> 2]; |
1562 |
|
/* No need to convert endianness, since it's only a 0-test. */ |
1563 |
|
|
1564 |
|
/* This makes execution continue on the first teqs instruction, |
1565 |
|
which is fine. */ |
1566 |
|
if (rX != 0) { |
1567 |
|
instr(load_w0_word_u1_p1_imm)(cpu, ic); |
1568 |
|
return; |
1569 |
|
} |
1570 |
|
|
1571 |
|
if (rZ == 0) { |
1572 |
|
static int x = 0; |
1573 |
|
|
1574 |
|
/* Synch the program counter. */ |
1575 |
|
uint32_t low_pc = ((size_t)ic - (size_t) |
1576 |
|
cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); |
1577 |
|
cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) |
1578 |
|
<< ARM_INSTR_ALIGNMENT_SHIFT); |
1579 |
|
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
1580 |
|
|
1581 |
|
/* Quasi-idle for a while: */ |
1582 |
|
cpu->has_been_idling = 1; |
1583 |
|
if (cpu->machine->ncpus == 1 && (++x) == 100) { |
1584 |
|
usleep(50); |
1585 |
|
x = 0; |
1586 |
|
} |
1587 |
|
|
1588 |
|
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; |
1589 |
|
cpu->cd.arm.next_ic = ¬hing_call; |
1590 |
|
return; |
1591 |
|
} |
1592 |
|
|
1593 |
|
cpu->cd.arm.next_ic = &ic[5]; |
1594 |
|
} |
1595 |
|
|
1596 |
|
|
1597 |
|
/* |
1598 |
* strlen: |
* strlen: |
1599 |
* |
* |
1600 |
* S: e5f03001 ldrb rY,[rX,#1]! |
* S: e5f03001 ldrb rY,[rX,#1]! |
2331 |
|
|
2332 |
|
|
2333 |
/* |
/* |
2334 |
* Combine: cmps_b(): |
* Combine: cmps + beq, etc: |
2335 |
*/ |
*/ |
2336 |
void COMBINE(cmps_b)(struct cpu *cpu, |
void COMBINE(beq_etc)(struct cpu *cpu, |
2337 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2338 |
{ |
{ |
2339 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2362 |
!(ic[-1].arg[1] & 0x80000000)) { |
!(ic[-1].arg[1] & 0x80000000)) { |
2363 |
ic[-1].f = instr(tsts_lo_beq_samepage); |
ic[-1].f = instr(tsts_lo_beq_samepage); |
2364 |
} |
} |
2365 |
|
if (n_back >= 4 && |
2366 |
|
ic[-4].f == instr(load_w0_word_u1_p1_imm) && |
2367 |
|
ic[-4].arg[0] != ic[-4].arg[2] && |
2368 |
|
ic[-4].arg[1] == 0 && |
2369 |
|
ic[-4].arg[2] == ic[-3].arg[0] && |
2370 |
|
/* Note: The teqs+bne is already combined! */ |
2371 |
|
ic[-3].f == instr(teqs_bne_samepage) && |
2372 |
|
ic[-3].arg[1] == 0 && |
2373 |
|
ic[-2].f == instr(b_samepage__ne) && |
2374 |
|
ic[-1].f == instr(teqs) && |
2375 |
|
ic[-1].arg[0] != ic[-4].arg[0] && |
2376 |
|
ic[-1].arg[1] == 0) { |
2377 |
|
ic[-4].f = instr(netbsd_idle); |
2378 |
|
} |
2379 |
if (ic[-1].f == instr(teqs)) { |
if (ic[-1].f == instr(teqs)) { |
2380 |
ic[-1].f = instr(teqs_beq_samepage); |
ic[-1].f = instr(teqs_beq_samepage); |
2381 |
} |
} |
2533 |
|
|
2534 |
/* Read the instruction word from memory: */ |
/* Read the instruction word from memory: */ |
2535 |
page = cpu->cd.arm.host_load[addr >> 12]; |
page = cpu->cd.arm.host_load[addr >> 12]; |
2536 |
|
|
2537 |
if (page != NULL) { |
if (page != NULL) { |
2538 |
/* fatal("TRANSLATION HIT! 0x%08x\n", addr); */ |
/* fatal("TRANSLATION HIT! 0x%08x\n", addr); */ |
2539 |
memcpy(ib, page + (addr & 0xfff), sizeof(ib)); |
memcpy(ib, page + (addr & 0xfff), sizeof(ib)); |
2580 |
goto okay; |
goto okay; |
2581 |
} |
} |
2582 |
|
|
2583 |
fatal("TODO: ARM condition code 0x%x\n", |
if (!cpu->translation_readahead) |
2584 |
condition_code); |
fatal("TODO: ARM condition code 0x%x\n", |
2585 |
|
condition_code); |
2586 |
goto bad; |
goto bad; |
2587 |
} |
} |
2588 |
|
|
2624 |
if ((iword & 0x0f8000f0) == 0x00800090) { |
if ((iword & 0x0f8000f0) == 0x00800090) { |
2625 |
/* Long multiplication: */ |
/* Long multiplication: */ |
2626 |
if (s_bit) { |
if (s_bit) { |
2627 |
fatal("TODO: sbit mull\n"); |
if (!cpu->translation_readahead) |
2628 |
|
fatal("TODO: sbit mull\n"); |
2629 |
goto bad; |
goto bad; |
2630 |
} |
} |
2631 |
ic->f = cond_instr(mull); |
ic->f = cond_instr(mull); |
2633 |
break; |
break; |
2634 |
} |
} |
2635 |
if ((iword & 0x0f900ff0) == 0x01000050) { |
if ((iword & 0x0f900ff0) == 0x01000050) { |
2636 |
fatal("TODO: q{,d}{add,sub}\n"); |
if (!cpu->translation_readahead) |
2637 |
|
fatal("TODO: q{,d}{add,sub}\n"); |
2638 |
goto bad; |
goto bad; |
2639 |
} |
} |
2640 |
if ((iword & 0x0ff000d0) == 0x01200010) { |
if ((iword & 0x0ff000d0) == 0x01200010) { |
2707 |
ic->f = cond_instr(msr_imm); |
ic->f = cond_instr(msr_imm); |
2708 |
} else { |
} else { |
2709 |
if (rm == ARM_PC) { |
if (rm == ARM_PC) { |
2710 |
fatal("msr PC?\n"); |
if (!cpu->translation_readahead) |
2711 |
|
fatal("msr PC?\n"); |
2712 |
goto bad; |
goto bad; |
2713 |
} |
} |
2714 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2725 |
case 1: ic->arg[1] = 0x000000ff; break; |
case 1: ic->arg[1] = 0x000000ff; break; |
2726 |
case 8: ic->arg[1] = 0xff000000; break; |
case 8: ic->arg[1] = 0xff000000; break; |
2727 |
case 9: ic->arg[1] = 0xff0000ff; break; |
case 9: ic->arg[1] = 0xff0000ff; break; |
2728 |
default:fatal("unimpl a: msr regform\n"); |
default:if (!cpu->translation_readahead) |
2729 |
|
fatal("unimpl a: msr regform\n"); |
2730 |
goto bad; |
goto bad; |
2731 |
} |
} |
2732 |
break; |
break; |
2734 |
if ((iword & 0x0fbf0fff) == 0x010f0000) { |
if ((iword & 0x0fbf0fff) == 0x010f0000) { |
2735 |
/* mrs: move from CPSR/SPSR to a register: */ |
/* mrs: move from CPSR/SPSR to a register: */ |
2736 |
if (rd == ARM_PC) { |
if (rd == ARM_PC) { |
2737 |
fatal("mrs PC?\n"); |
if (!cpu->translation_readahead) |
2738 |
|
fatal("mrs PC?\n"); |
2739 |
goto bad; |
goto bad; |
2740 |
} |
} |
2741 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2781 |
} |
} |
2782 |
|
|
2783 |
if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) { |
if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) { |
2784 |
fatal("reg form blah blah\n"); |
if (!cpu->translation_readahead) |
2785 |
|
fatal("reg form blah blah\n"); |
2786 |
goto bad; |
goto bad; |
2787 |
} |
} |
2788 |
|
|
2904 |
else |
else |
2905 |
ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff]; |
ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff]; |
2906 |
if ((iword & 0x0e000010) == 0x06000010) { |
if ((iword & 0x0e000010) == 0x06000010) { |
2907 |
fatal("Not a Load/store TODO\n"); |
if (!cpu->translation_readahead) |
2908 |
|
fatal("Not a Load/store TODO\n"); |
2909 |
goto bad; |
goto bad; |
2910 |
} |
} |
2911 |
/* Special case: pc-relative load within the same page: */ |
/* Special case: pc-relative load within the same page: */ |
2928 |
/* ic->f = cond_instr(mov); */ |
/* ic->f = cond_instr(mov); */ |
2929 |
ic->f = arm_dpi_instr[condition_code + 16*0xd]; |
ic->f = arm_dpi_instr[condition_code + 16*0xd]; |
2930 |
ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]); |
ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]); |
2931 |
p = cpu->cd.arm.host_load[a >> 12]; |
p = page; |
2932 |
if (p != NULL) { |
if (p != NULL) { |
2933 |
memcpy(c, p + (a & 0xfff), len); |
memcpy(c, p + (a & 0xfff), len); |
2934 |
} else { |
} else { |
2935 |
if (!cpu->memory_rw(cpu, cpu->mem, a, |
fatal("Hm? Internal error in " |
2936 |
c, len, MEM_READ, CACHE_DATA)) { |
"cpu_arm_instr.c!\n"); |
2937 |
fatal("to_be_translated(): " |
goto bad; |
|
"read failed X: TODO\n"); |
|
|
goto bad; |
|
|
} |
|
2938 |
} |
} |
2939 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
2940 |
x = c[0] + (c[1]<<8) + |
x = c[0] + (c[1]<<8) + |
2991 |
} |
} |
2992 |
#endif |
#endif |
2993 |
if (rn == ARM_PC) { |
if (rn == ARM_PC) { |
2994 |
fatal("TODO: bdt with PC as base\n"); |
if (!cpu->translation_readahead) |
2995 |
|
fatal("TODO: bdt with PC as base\n"); |
2996 |
goto bad; |
goto bad; |
2997 |
} |
} |
2998 |
break; |
break; |
3002 |
if (main_opcode == 0x0a) { |
if (main_opcode == 0x0a) { |
3003 |
ic->f = cond_instr(b); |
ic->f = cond_instr(b); |
3004 |
samepage_function = cond_instr(b_samepage); |
samepage_function = cond_instr(b_samepage); |
3005 |
|
|
3006 |
|
/* Abort read-ahead on unconditional branches: */ |
3007 |
|
if (condition_code == 0xe && |
3008 |
|
cpu->translation_readahead > 1) |
3009 |
|
cpu->translation_readahead = 1; |
3010 |
|
|
3011 |
if (iword == 0xcaffffed) |
if (iword == 0xcaffffed) |
3012 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = |
3013 |
COMBINE(netbsd_memset); |
COMBINE(netbsd_memset); |
3072 |
if (main_opcode == 0xa && (condition_code <= 1 |
if (main_opcode == 0xa && (condition_code <= 1 |
3073 |
|| condition_code == 3 || condition_code == 8 |
|| condition_code == 3 || condition_code == 8 |
3074 |
|| condition_code == 12 || condition_code == 13)) |
|| condition_code == 12 || condition_code == 13)) |
3075 |
cpu->cd.arm.combination_check = COMBINE(cmps_b); |
cpu->cd.arm.combination_check = COMBINE(beq_etc); |
3076 |
|
|
3077 |
if (iword == 0x1afffffc) |
if (iword == 0x1afffffc) |
3078 |
cpu->cd.arm.combination_check = COMBINE(strlen); |
cpu->cd.arm.combination_check = COMBINE(strlen); |
3091 |
*/ |
*/ |
3092 |
if ((iword & 0x0fe00fff) == 0x0c400000) { |
if ((iword & 0x0fe00fff) == 0x0c400000) { |
3093 |
/* Special case: mar/mra DSP instructions */ |
/* Special case: mar/mra DSP instructions */ |
3094 |
fatal("TODO: mar/mra DSP instructions!\n"); |
if (!cpu->translation_readahead) |
3095 |
|
fatal("TODO: mar/mra DSP instructions!\n"); |
3096 |
/* Perhaps these are actually identical to MCRR/MRRC */ |
/* Perhaps these are actually identical to MCRR/MRRC */ |
3097 |
goto bad; |
goto bad; |
3098 |
} |
} |
3099 |
|
|
3100 |
if ((iword & 0x0fe00000) == 0x0c400000) { |
if ((iword & 0x0fe00000) == 0x0c400000) { |
3101 |
fatal("MCRR/MRRC: TODO\n"); |
if (!cpu->translation_readahead) |
3102 |
|
fatal("MCRR/MRRC: TODO\n"); |
3103 |
goto bad; |
goto bad; |
3104 |
} |
} |
3105 |
|
|
3113 |
ic->f = cond_instr(und); |
ic->f = cond_instr(und); |
3114 |
ic->arg[0] = addr & 0xfff; |
ic->arg[0] = addr & 0xfff; |
3115 |
#else |
#else |
3116 |
fatal("LDC/STC: TODO\n"); |
if (!cpu->translation_readahead) |
3117 |
|
fatal("LDC/STC: TODO\n"); |
3118 |
goto bad; |
goto bad; |
3119 |
#endif |
#endif |
3120 |
break; |
break; |
3123 |
if ((iword & 0x0ff00ff0) == 0x0e200010) { |
if ((iword & 0x0ff00ff0) == 0x0e200010) { |
3124 |
/* Special case: mia* DSP instructions */ |
/* Special case: mia* DSP instructions */ |
3125 |
/* See Intel's 27343601.pdf, page 16-20 */ |
/* See Intel's 27343601.pdf, page 16-20 */ |
3126 |
fatal("TODO: mia* DSP instructions!\n"); |
if (!cpu->translation_readahead) |
3127 |
|
fatal("TODO: mia* DSP instructions!\n"); |
3128 |
goto bad; |
goto bad; |
3129 |
} |
} |
3130 |
if (iword & 0x10) { |
if (iword & 0x10) { |
3157 |
ic->arg[0] = iword & 0x00ffffff; |
ic->arg[0] = iword & 0x00ffffff; |
3158 |
ic->f = cond_instr(swi_useremul); |
ic->f = cond_instr(swi_useremul); |
3159 |
} else { |
} else { |
3160 |
fatal("Bad userland SWI?\n"); |
if (!cpu->translation_readahead) |
3161 |
|
fatal("Bad userland SWI?\n"); |
3162 |
goto bad; |
goto bad; |
3163 |
} |
} |
3164 |
} |
} |