25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_arm_instr.c,v 1.26 2005/10/07 22:10:51 debug Exp $ |
* $Id: cpu_arm_instr.c,v 1.29 2005/10/11 03:31:28 debug Exp $ |
29 |
* |
* |
30 |
* ARM instructions. |
* ARM instructions. |
31 |
* |
* |
133 |
|
|
134 |
/*****************************************************************************/ |
/*****************************************************************************/ |
135 |
|
|
|
/* |
|
|
* update_c is set if the C flag should be updated with the last shifted/ |
|
|
* rotated bit. |
|
|
*/ |
|
|
uint32_t R(struct cpu *cpu, struct arm_instr_call *ic, |
|
|
uint32_t iword, int update_c) |
|
|
{ |
|
|
int rm = iword & 15, lastbit, t, c; |
|
|
uint32_t tmp = cpu->cd.arm.r[rm]; |
|
|
|
|
|
if ((iword & 0xff0)==0 && rm != ARM_PC) |
|
|
return tmp; |
|
|
|
|
|
t = (iword >> 4) & 7; |
|
|
c = (iword >> 7) & 31; |
|
|
lastbit = 0; |
|
|
|
|
|
if (rm == ARM_PC) { |
|
|
/* Calculate tmp from this instruction's PC + 8 */ |
|
|
uint32_t low_pc = ((size_t)ic - (size_t) |
|
|
cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); |
|
|
tmp &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << |
|
|
ARM_INSTR_ALIGNMENT_SHIFT); |
|
|
tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
|
|
tmp += 8; |
|
|
} |
|
|
|
|
|
if ((iword & 0xff0)==0 && rm == ARM_PC) |
|
|
return tmp; |
|
|
|
|
|
if ((t & 1) && (c >> 1) == ARM_PC) { |
|
|
fatal("TODO: R: rc = PC\n"); |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
switch (t) { |
|
|
case 0: /* lsl #c (c = 0..31) */ |
|
|
if (update_c) { |
|
|
if (c == 0) |
|
|
update_c = 0; |
|
|
else |
|
|
lastbit = (tmp << (c-1)) & 0x80000000; |
|
|
} |
|
|
tmp <<= c; |
|
|
break; |
|
|
case 1: /* lsl Rc */ |
|
|
c = cpu->cd.arm.r[c >> 1] & 255; |
|
|
if (c >= 32) |
|
|
c = 33; |
|
|
if (update_c) { |
|
|
if (c == 0) |
|
|
update_c = 0; |
|
|
else |
|
|
lastbit = ((uint64_t)tmp << (c-1)) & 0x80000000; |
|
|
} |
|
|
tmp = (uint64_t)tmp << c; |
|
|
break; |
|
|
case 2: /* lsr #c (c = 1..32) */ |
|
|
if (c == 0) |
|
|
c = 32; |
|
|
if (update_c) { |
|
|
lastbit = ((uint64_t)tmp >> (c-1)) & 1; |
|
|
} |
|
|
tmp = (uint64_t)tmp >> c; |
|
|
break; |
|
|
case 3: /* lsr Rc */ |
|
|
c = cpu->cd.arm.r[c >> 1] & 255; |
|
|
if (c >= 32) |
|
|
c = 33; |
|
|
if (update_c) { |
|
|
if (c == 0) |
|
|
update_c = 0; |
|
|
else |
|
|
lastbit = ((uint64_t)tmp >> (c-1)) & 1; |
|
|
} |
|
|
tmp = (uint64_t)tmp >> c; |
|
|
break; |
|
|
case 4: /* asr #c (c = 1..32) */ |
|
|
if (c == 0) |
|
|
c = 32; |
|
|
if (update_c) { |
|
|
lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1; |
|
|
} |
|
|
tmp = (int64_t)(int32_t)tmp >> c; |
|
|
break; |
|
|
case 5: /* asr Rc */ |
|
|
c = cpu->cd.arm.r[c >> 1] & 255; |
|
|
if (c >= 32) |
|
|
c = 33; |
|
|
if (update_c) { |
|
|
if (c == 0) |
|
|
update_c = 0; |
|
|
else |
|
|
lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1; |
|
|
} |
|
|
tmp = (int64_t)(int32_t)tmp >> c; |
|
|
break; |
|
|
case 6: /* ror 1..31 */ |
|
|
if (c == 0) { |
|
|
fatal("TODO: rrx\n"); |
|
|
exit(1); |
|
|
} |
|
|
if (update_c) |
|
|
lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1; |
|
|
tmp = (uint64_t)(((uint64_t)tmp << 32) | tmp) >> c; |
|
|
break; |
|
|
case 7: /* ror Rc */ |
|
|
c = cpu->cd.arm.r[c >> 1] & 255; |
|
|
if (update_c) { |
|
|
if (c == 0) |
|
|
update_c = 0; |
|
|
else { |
|
|
c &= 31; |
|
|
if (c == 0) |
|
|
lastbit = tmp & 0x80000000; |
|
|
else |
|
|
lastbit = ((int64_t)(int32_t)tmp |
|
|
>> (c-1)) & 1; |
|
|
tmp = (uint64_t)(((uint64_t)tmp << 32) |
|
|
| tmp) >> c; |
|
|
} |
|
|
} |
|
|
break; |
|
|
} |
|
|
if (update_c) { |
|
|
cpu->cd.arm.cpsr &= ~ARM_FLAG_C; |
|
|
if (lastbit) |
|
|
cpu->cd.arm.cpsr |= ARM_FLAG_C; |
|
|
} |
|
|
return tmp; |
|
|
} |
|
|
|
|
|
|
|
|
/*****************************************************************************/ |
|
|
|
|
136 |
|
|
137 |
/* |
/* |
138 |
* nop: Do nothing. |
* nop: Do nothing. |
802 |
extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *, |
extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *, |
803 |
struct arm_instr_call *); |
struct arm_instr_call *); |
804 |
|
|
805 |
|
extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *); |
806 |
|
|
807 |
extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *, |
extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *, |
808 |
struct arm_instr_call *); |
struct arm_instr_call *); |
809 |
X(cmps); |
X(cmps); |
829 |
int u_bit = iw & 0x00800000; |
int u_bit = iw & 0x00800000; |
830 |
int s_bit = iw & 0x00400000; |
int s_bit = iw & 0x00400000; |
831 |
int w_bit = iw & 0x00200000; |
int w_bit = iw & 0x00200000; |
832 |
int i, return_flag = 0, saved_mode = 0; |
int i, return_flag = 0; |
833 |
uint32_t new_values[16]; |
uint32_t new_values[16]; |
834 |
|
|
835 |
/* Synchronize the program counter: */ |
/* Synchronize the program counter: */ |
841 |
cpu->pc = cpu->cd.arm.r[ARM_PC]; |
cpu->pc = cpu->cd.arm.r[ARM_PC]; |
842 |
|
|
843 |
if (s_bit) { |
if (s_bit) { |
844 |
/* Load USR registers: */ |
/* Load to USR registers: */ |
845 |
if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) { |
if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) { |
846 |
fatal("[ bdt_load: s-bit: in usermode? ]\n"); |
fatal("[ bdt_load: s-bit: in usermode? ]\n"); |
847 |
s_bit = 0; |
s_bit = 0; |
848 |
} else if (iw & 0x8000) { |
} |
849 |
|
if (iw & 0x8000) { |
850 |
s_bit = 0; |
s_bit = 0; |
851 |
return_flag = 1; |
return_flag = 1; |
|
} else { |
|
|
/* Which saved mode to restore to: */ |
|
|
uint32_t spsr; |
|
|
switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { |
|
|
case ARM_MODE_FIQ32: |
|
|
spsr = cpu->cd.arm.spsr_fiq; break; |
|
|
case ARM_MODE_ABT32: |
|
|
spsr = cpu->cd.arm.spsr_abt; break; |
|
|
case ARM_MODE_UND32: |
|
|
spsr = cpu->cd.arm.spsr_und; break; |
|
|
case ARM_MODE_IRQ32: |
|
|
spsr = cpu->cd.arm.spsr_irq; break; |
|
|
case ARM_MODE_SVC32: |
|
|
spsr = cpu->cd.arm.spsr_svc; break; |
|
|
default:fatal("bdt_load (1): unimplemented mode %i\n", |
|
|
cpu->cd.arm.cpsr & ARM_FLAG_MODE); |
|
|
exit(1); |
|
|
} |
|
|
saved_mode = spsr & ARM_FLAG_MODE; |
|
852 |
} |
} |
853 |
} |
} |
854 |
|
|
918 |
if (!s_bit) { |
if (!s_bit) { |
919 |
cpu->cd.arm.r[i] = new_values[i]; |
cpu->cd.arm.r[i] = new_values[i]; |
920 |
} else { |
} else { |
921 |
switch (saved_mode) { |
switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { |
922 |
case ARM_MODE_USR32: |
case ARM_MODE_USR32: |
923 |
case ARM_MODE_SYS32: |
case ARM_MODE_SYS32: |
924 |
if (i >= 8 && i <= 14) |
cpu->cd.arm.r[i] = new_values[i]; |
|
cpu->cd.arm.default_r8_r14[i-8] = |
|
|
new_values[i]; |
|
|
else |
|
|
cpu->cd.arm.r[i] = new_values[i]; |
|
925 |
break; |
break; |
926 |
case ARM_MODE_FIQ32: |
case ARM_MODE_FIQ32: |
927 |
if (i >= 8 && i <= 14) |
if (i >= 8 && i <= 14) |
928 |
cpu->cd.arm.fiq_r8_r14[i-8] = |
cpu->cd.arm.default_r8_r14[i-8] = |
|
new_values[i]; |
|
|
else |
|
|
cpu->cd.arm.r[i] = new_values[i]; |
|
|
break; |
|
|
case ARM_MODE_IRQ32: |
|
|
if (i >= 13 && i <= 14) |
|
|
cpu->cd.arm.irq_r13_r14[i-13] = |
|
929 |
new_values[i]; |
new_values[i]; |
930 |
else |
else |
931 |
cpu->cd.arm.r[i] = new_values[i]; |
cpu->cd.arm.r[i] = new_values[i]; |
932 |
break; |
break; |
933 |
case ARM_MODE_SVC32: |
case ARM_MODE_SVC32: |
|
if (i >= 13 && i <= 14) |
|
|
cpu->cd.arm.svc_r13_r14[i-13] = |
|
|
new_values[i]; |
|
|
else |
|
|
cpu->cd.arm.r[i] = new_values[i]; |
|
|
break; |
|
934 |
case ARM_MODE_ABT32: |
case ARM_MODE_ABT32: |
|
if (i >= 13 && i <= 14) |
|
|
cpu->cd.arm.abt_r13_r14[i-13] = |
|
|
new_values[i]; |
|
|
else |
|
|
cpu->cd.arm.r[i] = new_values[i]; |
|
|
break; |
|
935 |
case ARM_MODE_UND32: |
case ARM_MODE_UND32: |
936 |
|
case ARM_MODE_IRQ32: |
937 |
if (i >= 13 && i <= 14) |
if (i >= 13 && i <= 14) |
938 |
cpu->cd.arm.und_r13_r14[i-13] = |
cpu->cd.arm.default_r8_r14[i-8] = |
939 |
new_values[i]; |
new_values[i]; |
940 |
else |
else |
941 |
cpu->cd.arm.r[i] = new_values[i]; |
cpu->cd.arm.r[i] = new_values[i]; |
1013 |
int u_bit = iw & 0x00800000; |
int u_bit = iw & 0x00800000; |
1014 |
int s_bit = iw & 0x00400000; |
int s_bit = iw & 0x00400000; |
1015 |
int w_bit = iw & 0x00200000; |
int w_bit = iw & 0x00200000; |
1016 |
int i, saved_mode = 0; |
int i; |
|
|
|
|
if (s_bit) { |
|
|
/* Store USR (or saved) registers: */ |
|
|
uint32_t spsr; |
|
|
switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { |
|
|
case ARM_MODE_FIQ32: |
|
|
spsr = cpu->cd.arm.spsr_fiq; break; |
|
|
case ARM_MODE_ABT32: |
|
|
spsr = cpu->cd.arm.spsr_abt; break; |
|
|
case ARM_MODE_UND32: |
|
|
spsr = cpu->cd.arm.spsr_und; break; |
|
|
case ARM_MODE_IRQ32: |
|
|
spsr = cpu->cd.arm.spsr_irq; break; |
|
|
case ARM_MODE_SVC32: |
|
|
spsr = cpu->cd.arm.spsr_svc; break; |
|
|
default:fatal("bdt_store: unimplemented mode %i\n", |
|
|
cpu->cd.arm.cpsr & ARM_FLAG_MODE); |
|
|
exit(1); |
|
|
} |
|
|
saved_mode = spsr & ARM_FLAG_MODE; |
|
|
} |
|
1017 |
|
|
1018 |
/* Synchronize the program counter: */ |
/* Synchronize the program counter: */ |
1019 |
low_pc = ((size_t)ic - (size_t) |
low_pc = ((size_t)ic - (size_t) |
1032 |
value = cpu->cd.arm.r[i]; |
value = cpu->cd.arm.r[i]; |
1033 |
|
|
1034 |
if (s_bit) { |
if (s_bit) { |
1035 |
switch (saved_mode) { |
switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { |
1036 |
case ARM_MODE_FIQ32: |
case ARM_MODE_FIQ32: |
1037 |
if (i >= 8 && i <= 14) |
if (i >= 8 && i <= 14) |
1038 |
value = cpu->cd.arm.fiq_r8_r14[i-8]; |
value = cpu->cd.arm.default_r8_r14[i-8]; |
1039 |
break; |
break; |
1040 |
case ARM_MODE_ABT32: |
case ARM_MODE_ABT32: |
|
if (i >= 13 && i <= 14) |
|
|
value = cpu->cd.arm.abt_r13_r14[i-13]; |
|
|
break; |
|
1041 |
case ARM_MODE_UND32: |
case ARM_MODE_UND32: |
|
if (i >= 13 && i <= 14) |
|
|
value = cpu->cd.arm.und_r13_r14[i-13]; |
|
|
break; |
|
1042 |
case ARM_MODE_IRQ32: |
case ARM_MODE_IRQ32: |
|
if (i >= 13 && i <= 14) |
|
|
value = cpu->cd.arm.irq_r13_r14[i-13]; |
|
|
break; |
|
1043 |
case ARM_MODE_SVC32: |
case ARM_MODE_SVC32: |
1044 |
if (i >= 13 && i <= 14) |
if (i >= 13 && i <= 14) |
1045 |
value = cpu->cd.arm.svc_r13_r14[i-13]; |
value = cpu->cd.arm.default_r8_r14[i-8]; |
1046 |
break; |
break; |
1047 |
case ARM_MODE_USR32: |
case ARM_MODE_USR32: |
1048 |
case ARM_MODE_SYS32: |
case ARM_MODE_SYS32: |
|
if (i >= 8 && i <= 14) |
|
|
value = cpu->cd.arm.default_r8_r14[i-8]; |
|
1049 |
break; |
break; |
1050 |
} |
} |
1051 |
} |
} |
1550 |
+ (u_bit? 256 : 0) + (p_bit? 512 : 0) |
+ (u_bit? 256 : 0) + (p_bit? 512 : 0) |
1551 |
+ (regform? 1024 : 0)]; |
+ (regform? 1024 : 0)]; |
1552 |
if (regform) |
if (regform) |
1553 |
ic->arg[1] = iword & 0xf; |
ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf]; |
1554 |
else |
else |
1555 |
ic->arg[1] = imm; |
ic->arg[1] = imm; |
1556 |
break; |
break; |
1585 |
else |
else |
1586 |
regform = 0; |
regform = 0; |
1587 |
|
|
1588 |
if (regform) |
if (regform) { |
1589 |
ic->arg[1] = iword; |
/* 0x1000 signifies Carry bit update on rotation, |
1590 |
else { |
which is not necessary for add,adc,sub,sbc, |
1591 |
|
rsb,rsc,cmp, or cmn, because they update the |
1592 |
|
Carry bit manually anyway. */ |
1593 |
|
int q = 0x1000; |
1594 |
|
if (s_bit == 0) |
1595 |
|
q = 0; |
1596 |
|
if ((secondary_opcode >= 2 && secondary_opcode <= 7) |
1597 |
|
|| secondary_opcode==0xa || secondary_opcode==0xb) |
1598 |
|
q = 0; |
1599 |
|
ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q]; |
1600 |
|
} else { |
1601 |
imm = iword & 0xff; |
imm = iword & 0xff; |
1602 |
while (r8-- > 0) |
while (r8-- > 0) |
1603 |
imm = (imm >> 2) | ((imm & 3) << 30); |
imm = (imm >> 2) | ((imm & 3) << 30); |
1636 |
if (main_opcode < 6) |
if (main_opcode < 6) |
1637 |
ic->arg[1] = imm; |
ic->arg[1] = imm; |
1638 |
else |
else |
1639 |
ic->arg[1] = iword; |
ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff]; |
1640 |
if ((iword & 0x0e000010) == 0x06000010) { |
if ((iword & 0x0e000010) == 0x06000010) { |
1641 |
fatal("Not a Load/store TODO\n"); |
fatal("Not a Load/store TODO\n"); |
1642 |
goto bad; |
goto bad; |