25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_arm_instr.c,v 1.71 2007/04/20 13:47:53 debug Exp $ |
* $Id: cpu_arm_instr.c,v 1.74 2007/06/14 04:53:46 debug Exp $ |
29 |
* |
* |
30 |
* ARM instructions. |
* ARM instructions. |
31 |
* |
* |
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 |
|
/* Synch the program counter. */ |
1573 |
|
uint32_t low_pc = ((size_t)ic - (size_t) |
1574 |
|
cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); |
1575 |
|
cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) |
1576 |
|
<< ARM_INSTR_ALIGNMENT_SHIFT); |
1577 |
|
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
1578 |
|
|
1579 |
|
/* Quasi-idle for a while: */ |
1580 |
|
cpu->has_been_idling = 1; |
1581 |
|
if (cpu->machine->ncpus == 1) |
1582 |
|
usleep(50); |
1583 |
|
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT; |
1584 |
|
|
1585 |
|
cpu->cd.arm.next_ic = ¬hing_call; |
1586 |
|
return; |
1587 |
|
} |
1588 |
|
|
1589 |
|
cpu->cd.arm.next_ic = &ic[5]; |
1590 |
|
} |
1591 |
|
|
1592 |
|
|
1593 |
|
/* |
1594 |
* strlen: |
* strlen: |
1595 |
* |
* |
1596 |
* S: e5f03001 ldrb rY,[rX,#1]! |
* S: e5f03001 ldrb rY,[rX,#1]! |
2327 |
|
|
2328 |
|
|
2329 |
/* |
/* |
2330 |
* Combine: cmps_b(): |
* Combine: cmps + beq, etc: |
2331 |
*/ |
*/ |
2332 |
void COMBINE(cmps_b)(struct cpu *cpu, |
void COMBINE(beq_etc)(struct cpu *cpu, |
2333 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2334 |
{ |
{ |
2335 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2358 |
!(ic[-1].arg[1] & 0x80000000)) { |
!(ic[-1].arg[1] & 0x80000000)) { |
2359 |
ic[-1].f = instr(tsts_lo_beq_samepage); |
ic[-1].f = instr(tsts_lo_beq_samepage); |
2360 |
} |
} |
2361 |
|
if (n_back >= 4 && |
2362 |
|
ic[-4].f == instr(load_w0_word_u1_p1_imm) && |
2363 |
|
ic[-4].arg[0] != ic[-4].arg[2] && |
2364 |
|
ic[-4].arg[1] == 0 && |
2365 |
|
ic[-4].arg[2] == ic[-3].arg[0] && |
2366 |
|
/* Note: The teqs+bne is already combined! */ |
2367 |
|
ic[-3].f == instr(teqs_bne_samepage) && |
2368 |
|
ic[-3].arg[1] == 0 && |
2369 |
|
ic[-2].f == instr(b_samepage__ne) && |
2370 |
|
ic[-1].f == instr(teqs) && |
2371 |
|
ic[-1].arg[0] != ic[-4].arg[0] && |
2372 |
|
ic[-1].arg[1] == 0) { |
2373 |
|
ic[-4].f = instr(netbsd_idle); |
2374 |
|
} |
2375 |
if (ic[-1].f == instr(teqs)) { |
if (ic[-1].f == instr(teqs)) { |
2376 |
ic[-1].f = instr(teqs_beq_samepage); |
ic[-1].f = instr(teqs_beq_samepage); |
2377 |
} |
} |
2575 |
goto okay; |
goto okay; |
2576 |
} |
} |
2577 |
|
|
2578 |
fatal("TODO: ARM condition code 0x%x\n", |
if (!cpu->translation_readahead) |
2579 |
condition_code); |
fatal("TODO: ARM condition code 0x%x\n", |
2580 |
|
condition_code); |
2581 |
goto bad; |
goto bad; |
2582 |
} |
} |
2583 |
|
|
2619 |
if ((iword & 0x0f8000f0) == 0x00800090) { |
if ((iword & 0x0f8000f0) == 0x00800090) { |
2620 |
/* Long multiplication: */ |
/* Long multiplication: */ |
2621 |
if (s_bit) { |
if (s_bit) { |
2622 |
fatal("TODO: sbit mull\n"); |
if (!cpu->translation_readahead) |
2623 |
|
fatal("TODO: sbit mull\n"); |
2624 |
goto bad; |
goto bad; |
2625 |
} |
} |
2626 |
ic->f = cond_instr(mull); |
ic->f = cond_instr(mull); |
2628 |
break; |
break; |
2629 |
} |
} |
2630 |
if ((iword & 0x0f900ff0) == 0x01000050) { |
if ((iword & 0x0f900ff0) == 0x01000050) { |
2631 |
fatal("TODO: q{,d}{add,sub}\n"); |
if (!cpu->translation_readahead) |
2632 |
|
fatal("TODO: q{,d}{add,sub}\n"); |
2633 |
goto bad; |
goto bad; |
2634 |
} |
} |
2635 |
if ((iword & 0x0ff000d0) == 0x01200010) { |
if ((iword & 0x0ff000d0) == 0x01200010) { |
2702 |
ic->f = cond_instr(msr_imm); |
ic->f = cond_instr(msr_imm); |
2703 |
} else { |
} else { |
2704 |
if (rm == ARM_PC) { |
if (rm == ARM_PC) { |
2705 |
fatal("msr PC?\n"); |
if (!cpu->translation_readahead) |
2706 |
|
fatal("msr PC?\n"); |
2707 |
goto bad; |
goto bad; |
2708 |
} |
} |
2709 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2720 |
case 1: ic->arg[1] = 0x000000ff; break; |
case 1: ic->arg[1] = 0x000000ff; break; |
2721 |
case 8: ic->arg[1] = 0xff000000; break; |
case 8: ic->arg[1] = 0xff000000; break; |
2722 |
case 9: ic->arg[1] = 0xff0000ff; break; |
case 9: ic->arg[1] = 0xff0000ff; break; |
2723 |
default:fatal("unimpl a: msr regform\n"); |
default:if (!cpu->translation_readahead) |
2724 |
|
fatal("unimpl a: msr regform\n"); |
2725 |
goto bad; |
goto bad; |
2726 |
} |
} |
2727 |
break; |
break; |
2729 |
if ((iword & 0x0fbf0fff) == 0x010f0000) { |
if ((iword & 0x0fbf0fff) == 0x010f0000) { |
2730 |
/* mrs: move from CPSR/SPSR to a register: */ |
/* mrs: move from CPSR/SPSR to a register: */ |
2731 |
if (rd == ARM_PC) { |
if (rd == ARM_PC) { |
2732 |
fatal("mrs PC?\n"); |
if (!cpu->translation_readahead) |
2733 |
|
fatal("mrs PC?\n"); |
2734 |
goto bad; |
goto bad; |
2735 |
} |
} |
2736 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2776 |
} |
} |
2777 |
|
|
2778 |
if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) { |
if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) { |
2779 |
fatal("reg form blah blah\n"); |
if (!cpu->translation_readahead) |
2780 |
|
fatal("reg form blah blah\n"); |
2781 |
goto bad; |
goto bad; |
2782 |
} |
} |
2783 |
|
|
2899 |
else |
else |
2900 |
ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff]; |
ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff]; |
2901 |
if ((iword & 0x0e000010) == 0x06000010) { |
if ((iword & 0x0e000010) == 0x06000010) { |
2902 |
fatal("Not a Load/store TODO\n"); |
if (!cpu->translation_readahead) |
2903 |
|
fatal("Not a Load/store TODO\n"); |
2904 |
goto bad; |
goto bad; |
2905 |
} |
} |
2906 |
/* Special case: pc-relative load within the same page: */ |
/* Special case: pc-relative load within the same page: */ |
2929 |
} else { |
} else { |
2930 |
if (!cpu->memory_rw(cpu, cpu->mem, a, |
if (!cpu->memory_rw(cpu, cpu->mem, a, |
2931 |
c, len, MEM_READ, CACHE_DATA)) { |
c, len, MEM_READ, CACHE_DATA)) { |
2932 |
fatal("to_be_translated(): " |
if (!cpu->translation_readahead) |
2933 |
"read failed X: TODO\n"); |
fatal("read failed X:" |
2934 |
|
" TODO\n"); |
2935 |
goto bad; |
goto bad; |
2936 |
} |
} |
2937 |
} |
} |
2990 |
} |
} |
2991 |
#endif |
#endif |
2992 |
if (rn == ARM_PC) { |
if (rn == ARM_PC) { |
2993 |
fatal("TODO: bdt with PC as base\n"); |
if (!cpu->translation_readahead) |
2994 |
|
fatal("TODO: bdt with PC as base\n"); |
2995 |
goto bad; |
goto bad; |
2996 |
} |
} |
2997 |
break; |
break; |
3001 |
if (main_opcode == 0x0a) { |
if (main_opcode == 0x0a) { |
3002 |
ic->f = cond_instr(b); |
ic->f = cond_instr(b); |
3003 |
samepage_function = cond_instr(b_samepage); |
samepage_function = cond_instr(b_samepage); |
3004 |
|
|
3005 |
|
/* Abort read-ahead on unconditional branches: */ |
3006 |
|
if (condition_code == 0xe && |
3007 |
|
cpu->translation_readahead > 1) |
3008 |
|
cpu->translation_readahead = 1; |
3009 |
|
|
3010 |
if (iword == 0xcaffffed) |
if (iword == 0xcaffffed) |
3011 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = |
3012 |
COMBINE(netbsd_memset); |
COMBINE(netbsd_memset); |
3071 |
if (main_opcode == 0xa && (condition_code <= 1 |
if (main_opcode == 0xa && (condition_code <= 1 |
3072 |
|| condition_code == 3 || condition_code == 8 |
|| condition_code == 3 || condition_code == 8 |
3073 |
|| condition_code == 12 || condition_code == 13)) |
|| condition_code == 12 || condition_code == 13)) |
3074 |
cpu->cd.arm.combination_check = COMBINE(cmps_b); |
cpu->cd.arm.combination_check = COMBINE(beq_etc); |
3075 |
|
|
3076 |
if (iword == 0x1afffffc) |
if (iword == 0x1afffffc) |
3077 |
cpu->cd.arm.combination_check = COMBINE(strlen); |
cpu->cd.arm.combination_check = COMBINE(strlen); |
3090 |
*/ |
*/ |
3091 |
if ((iword & 0x0fe00fff) == 0x0c400000) { |
if ((iword & 0x0fe00fff) == 0x0c400000) { |
3092 |
/* Special case: mar/mra DSP instructions */ |
/* Special case: mar/mra DSP instructions */ |
3093 |
fatal("TODO: mar/mra DSP instructions!\n"); |
if (!cpu->translation_readahead) |
3094 |
|
fatal("TODO: mar/mra DSP instructions!\n"); |
3095 |
/* Perhaps these are actually identical to MCRR/MRRC */ |
/* Perhaps these are actually identical to MCRR/MRRC */ |
3096 |
goto bad; |
goto bad; |
3097 |
} |
} |
3098 |
|
|
3099 |
if ((iword & 0x0fe00000) == 0x0c400000) { |
if ((iword & 0x0fe00000) == 0x0c400000) { |
3100 |
fatal("MCRR/MRRC: TODO\n"); |
if (!cpu->translation_readahead) |
3101 |
|
fatal("MCRR/MRRC: TODO\n"); |
3102 |
goto bad; |
goto bad; |
3103 |
} |
} |
3104 |
|
|
3112 |
ic->f = cond_instr(und); |
ic->f = cond_instr(und); |
3113 |
ic->arg[0] = addr & 0xfff; |
ic->arg[0] = addr & 0xfff; |
3114 |
#else |
#else |
3115 |
fatal("LDC/STC: TODO\n"); |
if (!cpu->translation_readahead) |
3116 |
|
fatal("LDC/STC: TODO\n"); |
3117 |
goto bad; |
goto bad; |
3118 |
#endif |
#endif |
3119 |
break; |
break; |
3122 |
if ((iword & 0x0ff00ff0) == 0x0e200010) { |
if ((iword & 0x0ff00ff0) == 0x0e200010) { |
3123 |
/* Special case: mia* DSP instructions */ |
/* Special case: mia* DSP instructions */ |
3124 |
/* See Intel's 27343601.pdf, page 16-20 */ |
/* See Intel's 27343601.pdf, page 16-20 */ |
3125 |
fatal("TODO: mia* DSP instructions!\n"); |
if (!cpu->translation_readahead) |
3126 |
|
fatal("TODO: mia* DSP instructions!\n"); |
3127 |
goto bad; |
goto bad; |
3128 |
} |
} |
3129 |
if (iword & 0x10) { |
if (iword & 0x10) { |
3156 |
ic->arg[0] = iword & 0x00ffffff; |
ic->arg[0] = iword & 0x00ffffff; |
3157 |
ic->f = cond_instr(swi_useremul); |
ic->f = cond_instr(swi_useremul); |
3158 |
} else { |
} else { |
3159 |
fatal("Bad userland SWI?\n"); |
if (!cpu->translation_readahead) |
3160 |
|
fatal("Bad userland SWI?\n"); |
3161 |
goto bad; |
goto bad; |
3162 |
} |
} |
3163 |
} |
} |