25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_sh_instr.c,v 1.56 2007/04/19 15:49:39 debug Exp $ |
* $Id: cpu_sh_instr.c,v 1.64 2007/06/28 13:36:47 debug Exp $ |
29 |
* |
* |
30 |
* SH instructions. |
* SH instructions. |
31 |
* |
* |
102 |
|
|
103 |
if (cpu->machine->ncpus == 1) { |
if (cpu->machine->ncpus == 1) { |
104 |
static int x = 0; |
static int x = 0; |
105 |
|
|
106 |
if ((++x) == 600) { |
if ((++x) == 600) { |
107 |
usleep(10); |
usleep(10); |
108 |
x = 0; |
x = 0; |
109 |
} |
} |
110 |
|
|
111 |
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; |
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; |
112 |
} |
} |
113 |
} |
} |
175 |
X(extu_b_rm_rn) { reg(ic->arg[1]) = (uint8_t)reg(ic->arg[0]); } |
X(extu_b_rm_rn) { reg(ic->arg[1]) = (uint8_t)reg(ic->arg[0]); } |
176 |
X(exts_w_rm_rn) { reg(ic->arg[1]) = (int16_t)reg(ic->arg[0]); } |
X(exts_w_rm_rn) { reg(ic->arg[1]) = (int16_t)reg(ic->arg[0]); } |
177 |
X(extu_w_rm_rn) { reg(ic->arg[1]) = (uint16_t)reg(ic->arg[0]); } |
X(extu_w_rm_rn) { reg(ic->arg[1]) = (uint16_t)reg(ic->arg[0]); } |
178 |
|
/* Note: rm and rn are the same on these: */ |
179 |
|
X(extu_b_rm) { reg(ic->arg[1]) = (uint8_t)reg(ic->arg[1]); } |
180 |
|
X(extu_w_rm) { reg(ic->arg[1]) = (uint16_t)reg(ic->arg[1]); } |
181 |
|
|
182 |
|
|
183 |
/* |
/* |
285 |
* arg[0] = int8_t imm, extended to at least int32_t |
* arg[0] = int8_t imm, extended to at least int32_t |
286 |
* arg[1] = ptr to rn |
* arg[1] = ptr to rn |
287 |
*/ |
*/ |
288 |
X(mov_imm_rn) { reg(ic->arg[1]) = (int32_t)ic->arg[0]; } |
X(mov_imm_rn) { reg(ic->arg[1]) = ic->arg[0]; } |
289 |
X(add_imm_rn) { reg(ic->arg[1]) += (int32_t)ic->arg[0]; } |
X(mov_0_rn) { reg(ic->arg[1]) = 0; } |
290 |
|
X(add_imm_rn) { reg(ic->arg[1]) += ic->arg[0]; } |
291 |
|
X(inc_rn) { reg(ic->arg[1]) ++; } |
292 |
|
X(add_4_rn) { reg(ic->arg[1]) += 4; } |
293 |
|
X(sub_4_rn) { reg(ic->arg[1]) -= 4; } |
294 |
|
X(dec_rn) { reg(ic->arg[1]) --; } |
295 |
|
|
296 |
|
|
297 |
/* |
/* |
1381 |
* sub_rm_rn: rn = rn - rm |
* sub_rm_rn: rn = rn - rm |
1382 |
* subc_rm_rn: rn = rn - rm - t; t = borrow |
* subc_rm_rn: rn = rn - rm - t; t = borrow |
1383 |
* tst_rm_rn: t = ((rm & rn) == 0) |
* tst_rm_rn: t = ((rm & rn) == 0) |
1384 |
|
* tst_rm: t = (rm == 0) |
1385 |
* xtrct_rm_rn: rn = (rn >> 16) | (rm << 16) |
* xtrct_rm_rn: rn = (rn >> 16) | (rm << 16) |
1386 |
* |
* |
1387 |
* arg[0] = ptr to rm |
* arg[0] = ptr to rm |
1423 |
else |
else |
1424 |
cpu->cd.sh.sr |= SH_SR_T; |
cpu->cd.sh.sr |= SH_SR_T; |
1425 |
} |
} |
1426 |
|
X(tst_rm) |
1427 |
|
{ |
1428 |
|
if (reg(ic->arg[0])) |
1429 |
|
cpu->cd.sh.sr &= ~SH_SR_T; |
1430 |
|
else |
1431 |
|
cpu->cd.sh.sr |= SH_SR_T; |
1432 |
|
} |
1433 |
X(xtrct_rm_rn) |
X(xtrct_rm_rn) |
1434 |
{ |
{ |
1435 |
uint32_t rn = reg(ic->arg[1]), rm = reg(ic->arg[0]); |
uint32_t rn = reg(ic->arg[1]), rm = reg(ic->arg[0]); |
1451 |
} |
} |
1452 |
X(div0s_rm_rn) |
X(div0s_rm_rn) |
1453 |
{ |
{ |
1454 |
int q = reg(ic->arg[1]) >> 31, m = reg(ic->arg[0]) >> 31; |
int q = reg(ic->arg[1]) & 0x80000000; |
1455 |
cpu->cd.sh.sr &= ~(SH_SR_Q | SH_SR_M | SH_SR_T); |
int m = reg(ic->arg[0]) & 0x80000000; |
1456 |
|
uint32_t new_sr = cpu->cd.sh.sr & ~(SH_SR_Q | SH_SR_M | SH_SR_T); |
1457 |
if (q) |
if (q) |
1458 |
cpu->cd.sh.sr |= SH_SR_Q; |
new_sr |= SH_SR_Q; |
1459 |
if (m) |
if (m) |
1460 |
cpu->cd.sh.sr |= SH_SR_M; |
new_sr |= SH_SR_M; |
1461 |
if (m ^ q) |
if (m ^ q) |
1462 |
cpu->cd.sh.sr |= SH_SR_T; |
new_sr |= SH_SR_T; |
1463 |
|
cpu->cd.sh.sr = new_sr; |
1464 |
} |
} |
1465 |
X(div1_rm_rn) |
X(div1_rm_rn) |
1466 |
{ |
{ |
1633 |
X(shll_rn) |
X(shll_rn) |
1634 |
{ |
{ |
1635 |
uint32_t rn = reg(ic->arg[1]); |
uint32_t rn = reg(ic->arg[1]); |
1636 |
if (rn >> 31) |
if (rn & 0x80000000) |
1637 |
cpu->cd.sh.sr |= SH_SR_T; |
cpu->cd.sh.sr |= SH_SR_T; |
1638 |
else |
else |
1639 |
cpu->cd.sh.sr &= ~SH_SR_T; |
cpu->cd.sh.sr &= ~SH_SR_T; |
1650 |
} |
} |
1651 |
X(rotl_rn) |
X(rotl_rn) |
1652 |
{ |
{ |
1653 |
uint32_t rn = reg(ic->arg[1]); |
uint32_t rn = reg(ic->arg[1]), x; |
1654 |
if (rn >> 31) |
if (rn & 0x80000000) { |
1655 |
|
x = 1; |
1656 |
cpu->cd.sh.sr |= SH_SR_T; |
cpu->cd.sh.sr |= SH_SR_T; |
1657 |
else |
} else { |
1658 |
|
x = 0; |
1659 |
cpu->cd.sh.sr &= ~SH_SR_T; |
cpu->cd.sh.sr &= ~SH_SR_T; |
1660 |
reg(ic->arg[1]) = (rn << 1) | (rn >> 31); |
} |
1661 |
|
reg(ic->arg[1]) = (rn << 1) | x; |
1662 |
} |
} |
1663 |
X(rotr_rn) |
X(rotr_rn) |
1664 |
{ |
{ |
1768 |
* braf: Like bra, but using a register instead of an immediate |
* braf: Like bra, but using a register instead of an immediate |
1769 |
* bsrf: Like braf, but also sets PR to the return address |
* bsrf: Like braf, but also sets PR to the return address |
1770 |
* |
* |
1771 |
* arg[0] = immediate offset relative to start of page |
* arg[0] = immediate offset relative to start of page, |
1772 |
|
* or ptr to target instruction, for samepage branches |
1773 |
* arg[1] = ptr to Rn (for braf/bsrf) |
* arg[1] = ptr to Rn (for braf/bsrf) |
1774 |
*/ |
*/ |
1775 |
X(bra) |
X(bra) |
1787 |
} else |
} else |
1788 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
1789 |
} |
} |
1790 |
|
X(bra_samepage) |
1791 |
|
{ |
1792 |
|
cpu->delay_slot = TO_BE_DELAYED; |
1793 |
|
ic[1].f(cpu, ic+1); |
1794 |
|
cpu->n_translated_instrs ++; |
1795 |
|
if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) |
1796 |
|
cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[0]; |
1797 |
|
cpu->delay_slot = NOT_DELAYED; |
1798 |
|
} |
1799 |
X(bsr) |
X(bsr) |
1800 |
{ |
{ |
1801 |
MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << |
MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << |
1815 |
} else |
} else |
1816 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
1817 |
} |
} |
1818 |
|
X(bsr_samepage) |
1819 |
|
{ |
1820 |
|
uint32_t old_pc; |
1821 |
|
SYNCH_PC; |
1822 |
|
old_pc = cpu->pc; |
1823 |
|
cpu->delay_slot = TO_BE_DELAYED; |
1824 |
|
ic[1].f(cpu, ic+1); |
1825 |
|
cpu->n_translated_instrs ++; |
1826 |
|
if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { |
1827 |
|
cpu->cd.sh.pr = old_pc + 4; |
1828 |
|
cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[0]; |
1829 |
|
} |
1830 |
|
cpu->delay_slot = NOT_DELAYED; |
1831 |
|
} |
1832 |
X(braf_rn) |
X(braf_rn) |
1833 |
{ |
{ |
1834 |
MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << |
MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << |
1872 |
* bf/s: Branch if false (with delay-slot) |
* bf/s: Branch if false (with delay-slot) |
1873 |
* |
* |
1874 |
* arg[0] = immediate offset relative to start of page |
* arg[0] = immediate offset relative to start of page |
1875 |
|
* arg[1] = for samepage functions, the new instruction pointer |
1876 |
*/ |
*/ |
1877 |
X(bt) |
X(bt) |
1878 |
{ |
{ |
1892 |
quick_pc_to_pointers(cpu); |
quick_pc_to_pointers(cpu); |
1893 |
} |
} |
1894 |
} |
} |
1895 |
|
X(bt_samepage) |
1896 |
|
{ |
1897 |
|
if (cpu->cd.sh.sr & SH_SR_T) |
1898 |
|
cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[1]; |
1899 |
|
} |
1900 |
|
X(bf_samepage) |
1901 |
|
{ |
1902 |
|
if (!(cpu->cd.sh.sr & SH_SR_T)) |
1903 |
|
cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[1]; |
1904 |
|
} |
1905 |
X(bt_s) |
X(bt_s) |
1906 |
{ |
{ |
1907 |
MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << |
MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << |
1940 |
} else |
} else |
1941 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
1942 |
} |
} |
1943 |
|
X(bt_s_samepage) |
1944 |
|
{ |
1945 |
|
int cond = cpu->cd.sh.sr & SH_SR_T; |
1946 |
|
cpu->delay_slot = TO_BE_DELAYED; |
1947 |
|
ic[1].f(cpu, ic+1); |
1948 |
|
cpu->n_translated_instrs ++; |
1949 |
|
if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { |
1950 |
|
cpu->delay_slot = NOT_DELAYED; |
1951 |
|
if (cond) |
1952 |
|
cpu->cd.sh.next_ic = |
1953 |
|
(struct sh_instr_call *) ic->arg[1]; |
1954 |
|
else |
1955 |
|
cpu->cd.sh.next_ic ++; |
1956 |
|
} else |
1957 |
|
cpu->delay_slot = NOT_DELAYED; |
1958 |
|
} |
1959 |
|
X(bf_s_samepage) |
1960 |
|
{ |
1961 |
|
int cond = !(cpu->cd.sh.sr & SH_SR_T); |
1962 |
|
cpu->delay_slot = TO_BE_DELAYED; |
1963 |
|
ic[1].f(cpu, ic+1); |
1964 |
|
cpu->n_translated_instrs ++; |
1965 |
|
if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { |
1966 |
|
cpu->delay_slot = NOT_DELAYED; |
1967 |
|
if (cond) |
1968 |
|
cpu->cd.sh.next_ic = |
1969 |
|
(struct sh_instr_call *) ic->arg[1]; |
1970 |
|
else |
1971 |
|
cpu->cd.sh.next_ic ++; |
1972 |
|
} else |
1973 |
|
cpu->delay_slot = NOT_DELAYED; |
1974 |
|
} |
1975 |
|
|
1976 |
|
|
1977 |
/* |
/* |
2882 |
*/ |
*/ |
2883 |
X(to_be_translated) |
X(to_be_translated) |
2884 |
{ |
{ |
2885 |
uint64_t addr, low_pc; |
uint32_t addr, low_pc, iword; |
|
uint32_t iword; |
|
2886 |
unsigned char *page; |
unsigned char *page; |
2887 |
unsigned char ib[4]; |
unsigned char ib[2]; |
2888 |
int main_opcode, isize = cpu->cd.sh.compact? 2 : sizeof(ib); |
int main_opcode, isize = sizeof(ib); |
2889 |
int in_crosspage_delayslot = 0, r8, r4, lo4, lo8; |
int in_crosspage_delayslot = 0, r8, r4, lo4, lo8; |
2890 |
/* void (*samepage_function)(struct cpu *, struct sh_instr_call *); */ |
void (*samepage_function)(struct cpu *, struct sh_instr_call *); |
2891 |
|
|
2892 |
/* Figure out the (virtual) address of the instruction: */ |
/* Figure out the (virtual) address of the instruction: */ |
2893 |
low_pc = ((size_t)ic - (size_t)cpu->cd.sh.cur_ic_page) |
low_pc = ((size_t)ic - (size_t)cpu->cd.sh.cur_ic_page) |
2907 |
addr &= ~((1 << SH_INSTR_ALIGNMENT_SHIFT) - 1); |
addr &= ~((1 << SH_INSTR_ALIGNMENT_SHIFT) - 1); |
2908 |
|
|
2909 |
/* Read the instruction word from memory: */ |
/* Read the instruction word from memory: */ |
|
#ifdef MODE32 |
|
2910 |
page = cpu->cd.sh.host_load[(uint32_t)addr >> 12]; |
page = cpu->cd.sh.host_load[(uint32_t)addr >> 12]; |
|
#else |
|
|
{ |
|
|
const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; |
|
|
const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; |
|
|
const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; |
|
|
uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; |
|
|
uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; |
|
|
uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- |
|
|
DYNTRANS_L3N)) & mask3; |
|
|
struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.sh.l1_64[x1]; |
|
|
struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; |
|
|
page = l3->host_load[x3]; |
|
|
} |
|
|
#endif |
|
2911 |
|
|
2912 |
if (page != NULL) { |
if (page != NULL) { |
2913 |
/* fatal("TRANSLATION HIT!\n"); */ |
/* fatal("TRANSLATION HIT!\n"); */ |
2921 |
} |
} |
2922 |
} |
} |
2923 |
|
|
2924 |
if (cpu->cd.sh.compact) { |
iword = *((uint16_t *)&ib[0]); |
2925 |
iword = *((uint16_t *)&ib[0]); |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
2926 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
iword = LE16_TO_HOST(iword); |
2927 |
iword = LE16_TO_HOST(iword); |
else |
2928 |
else |
iword = BE16_TO_HOST(iword); |
2929 |
iword = BE16_TO_HOST(iword); |
main_opcode = iword >> 12; |
2930 |
main_opcode = iword >> 12; |
r8 = (iword >> 8) & 0xf; |
2931 |
r8 = (iword >> 8) & 0xf; |
r4 = (iword >> 4) & 0xf; |
2932 |
r4 = (iword >> 4) & 0xf; |
lo8 = iword & 0xff; |
2933 |
lo8 = iword & 0xff; |
lo4 = iword & 0xf; |
|
lo4 = iword & 0xf; |
|
|
} else { |
|
|
iword = *((uint32_t *)&ib[0]); |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
|
|
iword = LE32_TO_HOST(iword); |
|
|
else |
|
|
iword = BE32_TO_HOST(iword); |
|
|
main_opcode = -1; /* TODO */ |
|
|
fatal("SH5/SH64 isn't implemented yet. Sorry.\n"); |
|
|
goto bad; |
|
|
} |
|
2934 |
|
|
2935 |
|
|
2936 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
3025 |
case 0x09: /* NOP */ |
case 0x09: /* NOP */ |
3026 |
ic->f = instr(nop); |
ic->f = instr(nop); |
3027 |
if (iword & 0x0f00) { |
if (iword & 0x0f00) { |
3028 |
fatal("Unimplemented NOP variant?\n"); |
if (!cpu->translation_readahead) |
3029 |
|
fatal("Unimplemented NOP" |
3030 |
|
" variant?\n"); |
3031 |
goto bad; |
goto bad; |
3032 |
} |
} |
3033 |
break; |
break; |
3107 |
ic->arg[0] = (size_t)&cpu->cd.sh.dbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.dbr; |
3108 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; |
3109 |
break; |
break; |
3110 |
default:fatal("Unimplemented opcode 0x%x,0x%03x\n", |
default:if (!cpu->translation_readahead) |
3111 |
main_opcode, iword & 0xfff); |
fatal("Unimplemented opcode 0x%x," |
3112 |
|
"0x%03x\n", main_opcode, |
3113 |
|
iword & 0xfff); |
3114 |
goto bad; |
goto bad; |
3115 |
} |
} |
3116 |
} |
} |
3146 |
break; |
break; |
3147 |
case 0x8: /* TST Rm,Rn */ |
case 0x8: /* TST Rm,Rn */ |
3148 |
ic->f = instr(tst_rm_rn); |
ic->f = instr(tst_rm_rn); |
3149 |
|
if (r8 == r4) |
3150 |
|
ic->f = instr(tst_rm); |
3151 |
break; |
break; |
3152 |
case 0x9: /* AND Rm,Rn */ |
case 0x9: /* AND Rm,Rn */ |
3153 |
ic->f = instr(and_rm_rn); |
ic->f = instr(and_rm_rn); |
3170 |
case 0xf: /* MULS.W Rm,Rn */ |
case 0xf: /* MULS.W Rm,Rn */ |
3171 |
ic->f = instr(muls_w_rm_rn); |
ic->f = instr(muls_w_rm_rn); |
3172 |
break; |
break; |
3173 |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
default:if (!cpu->translation_readahead) |
3174 |
main_opcode, lo4); |
fatal("Unimplemented opcode 0x%x,0x%x\n", |
3175 |
|
main_opcode, lo4); |
3176 |
goto bad; |
goto bad; |
3177 |
} |
} |
3178 |
break; |
break; |
3215 |
case 0xe: /* ADDC Rm,Rn */ |
case 0xe: /* ADDC Rm,Rn */ |
3216 |
ic->f = instr(addc_rm_rn); |
ic->f = instr(addc_rm_rn); |
3217 |
break; |
break; |
3218 |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
default:if (!cpu->translation_readahead) |
3219 |
main_opcode, lo4); |
fatal("Unimplemented opcode 0x%x,0x%x\n", |
3220 |
|
main_opcode, lo4); |
3221 |
goto bad; |
goto bad; |
3222 |
} |
} |
3223 |
break; |
break; |
3440 |
ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; |
ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; |
3441 |
ic->arg[1] = (size_t)&cpu->cd.sh.dbr; |
ic->arg[1] = (size_t)&cpu->cd.sh.dbr; |
3442 |
break; |
break; |
3443 |
default:fatal("Unimplemented opcode 0x%x,0x%02x\n", |
default:if (!cpu->translation_readahead) |
3444 |
main_opcode, lo8); |
fatal("Unimplemented opcode 0x%x," |
3445 |
|
"0x%02x\n", main_opcode, lo8); |
3446 |
goto bad; |
goto bad; |
3447 |
} |
} |
3448 |
} |
} |
3502 |
break; |
break; |
3503 |
case 0xc: /* EXTU.B Rm,Rn */ |
case 0xc: /* EXTU.B Rm,Rn */ |
3504 |
ic->f = instr(extu_b_rm_rn); |
ic->f = instr(extu_b_rm_rn); |
3505 |
|
if (r8 == r4) |
3506 |
|
ic->f = instr(extu_b_rm); |
3507 |
break; |
break; |
3508 |
case 0xd: /* EXTU.W Rm,Rn */ |
case 0xd: /* EXTU.W Rm,Rn */ |
3509 |
ic->f = instr(extu_w_rm_rn); |
ic->f = instr(extu_w_rm_rn); |
3510 |
|
if (r8 == r4) |
3511 |
|
ic->f = instr(extu_w_rm); |
3512 |
break; |
break; |
3513 |
case 0xe: /* EXTS.B Rm,Rn */ |
case 0xe: /* EXTS.B Rm,Rn */ |
3514 |
ic->f = instr(exts_b_rm_rn); |
ic->f = instr(exts_b_rm_rn); |
3516 |
case 0xf: /* EXTS.W Rm,Rn */ |
case 0xf: /* EXTS.W Rm,Rn */ |
3517 |
ic->f = instr(exts_w_rm_rn); |
ic->f = instr(exts_w_rm_rn); |
3518 |
break; |
break; |
3519 |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
default:if (!cpu->translation_readahead) |
3520 |
main_opcode, lo4); |
fatal("Unimplemented opcode 0x%x,0x%x\n", |
3521 |
|
main_opcode, lo4); |
3522 |
goto bad; |
goto bad; |
3523 |
} |
} |
3524 |
break; |
break; |
3526 |
case 0x7: /* ADD #imm,Rn */ |
case 0x7: /* ADD #imm,Rn */ |
3527 |
ic->f = instr(add_imm_rn); |
ic->f = instr(add_imm_rn); |
3528 |
ic->arg[0] = (int8_t)lo8; |
ic->arg[0] = (int8_t)lo8; |
3529 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
3530 |
|
if (lo8 == 1) |
3531 |
|
ic->f = instr(inc_rn); |
3532 |
|
if (lo8 == 4) |
3533 |
|
ic->f = instr(add_4_rn); |
3534 |
|
if (lo8 == 0xfc) |
3535 |
|
ic->f = instr(sub_4_rn); |
3536 |
|
if (lo8 == 0xff) |
3537 |
|
ic->f = instr(dec_rn); |
3538 |
break; |
break; |
3539 |
|
|
3540 |
case 0x8: |
case 0x8: |
3542 |
ic->arg[0] = (int8_t)lo8 * 2 + |
ic->arg[0] = (int8_t)lo8 * 2 + |
3543 |
(addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
(addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
3544 |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; |
3545 |
|
samepage_function = NULL; |
3546 |
|
|
3547 |
switch (r8) { |
switch (r8) { |
3548 |
case 0x0: /* MOV.B R0,@(disp,Rn) */ |
case 0x0: /* MOV.B R0,@(disp,Rn) */ |
3549 |
ic->f = instr(mov_b_r0_disp_rn); |
ic->f = instr(mov_b_r0_disp_rn); |
3571 |
break; |
break; |
3572 |
case 0x9: /* BT (disp,PC) */ |
case 0x9: /* BT (disp,PC) */ |
3573 |
ic->f = instr(bt); |
ic->f = instr(bt); |
3574 |
|
samepage_function = instr(bt_samepage); |
3575 |
break; |
break; |
3576 |
case 0xb: /* BF (disp,PC) */ |
case 0xb: /* BF (disp,PC) */ |
3577 |
ic->f = instr(bf); |
ic->f = instr(bf); |
3578 |
|
samepage_function = instr(bf_samepage); |
3579 |
break; |
break; |
3580 |
case 0xd: /* BT/S (disp,PC) */ |
case 0xd: /* BT/S (disp,PC) */ |
3581 |
ic->f = instr(bt_s); |
ic->f = instr(bt_s); |
3582 |
|
samepage_function = instr(bt_s_samepage); |
3583 |
break; |
break; |
3584 |
case 0xf: /* BF/S (disp,PC) */ |
case 0xf: /* BF/S (disp,PC) */ |
3585 |
ic->f = instr(bf_s); |
ic->f = instr(bf_s); |
3586 |
|
samepage_function = instr(bf_s_samepage); |
3587 |
break; |
break; |
3588 |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
default:if (!cpu->translation_readahead) |
3589 |
main_opcode, r8); |
fatal("Unimplemented opcode 0x%x,0x%x\n", |
3590 |
|
main_opcode, r8); |
3591 |
goto bad; |
goto bad; |
3592 |
} |
} |
3593 |
|
|
3594 |
|
/* samepage branches: */ |
3595 |
|
if (samepage_function != NULL && ic->arg[0] < 0x1000 && |
3596 |
|
(addr & 0xfff) < 0xffe) { |
3597 |
|
ic->arg[1] = (size_t) (cpu->cd.sh.cur_ic_page + |
3598 |
|
(ic->arg[0] >> SH_INSTR_ALIGNMENT_SHIFT)); |
3599 |
|
ic->f = samepage_function; |
3600 |
|
} |
3601 |
|
|
3602 |
break; |
break; |
3603 |
|
|
3604 |
case 0x9: /* MOV.W @(disp,PC),Rn */ |
case 0x9: /* MOV.W @(disp,PC),Rn */ |
3605 |
ic->f = instr(mov_w_disp_pc_rn); |
ic->f = instr(mov_w_disp_pc_rn); |
3606 |
ic->arg[0] = lo8 * 2 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
ic->arg[0] = lo8 * 2 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
3607 |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; |
3608 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
|
3609 |
|
/* If the word is reachable from the same page as the |
3610 |
|
current address, then optimize it as a mov_imm_rn: */ |
3611 |
|
if (ic->arg[0] < 0x1000 && page != NULL) { |
3612 |
|
uint16_t *p = (uint16_t *) page; |
3613 |
|
uint16_t data = p[ic->arg[0] >> 1]; |
3614 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3615 |
|
data = LE16_TO_HOST(data); |
3616 |
|
else |
3617 |
|
data = BE16_TO_HOST(data); |
3618 |
|
ic->f = instr(mov_imm_rn); |
3619 |
|
ic->arg[0] = (int16_t) data; |
3620 |
|
} |
3621 |
break; |
break; |
3622 |
|
|
3623 |
case 0xa: /* BRA disp */ |
case 0xa: /* BRA disp */ |
3624 |
case 0xb: /* BSR disp */ |
case 0xb: /* BSR disp */ |
3625 |
ic->f = main_opcode == 0xa? instr(bra) : instr(bsr); |
samepage_function = NULL; |
3626 |
|
|
3627 |
|
switch (main_opcode) { |
3628 |
|
case 0xa: |
3629 |
|
ic->f = instr(bra); |
3630 |
|
samepage_function = instr(bra_samepage); |
3631 |
|
break; |
3632 |
|
case 0xb: |
3633 |
|
ic->f = instr(bsr); |
3634 |
|
samepage_function = instr(bsr_samepage); |
3635 |
|
break; |
3636 |
|
} |
3637 |
|
|
3638 |
ic->arg[0] = (int32_t) ( (addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
ic->arg[0] = (int32_t) ( (addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
3639 |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4 + |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4 + |
3640 |
(((int32_t)(int16_t)((iword & 0xfff) << 4)) >> 3) ); |
(((int32_t)(int16_t)((iword & 0xfff) << 4)) >> 3) ); |
3641 |
|
|
3642 |
|
/* samepage branches: */ |
3643 |
|
if (samepage_function != NULL && ic->arg[0] < 0x1000 && |
3644 |
|
(addr & 0xfff) < 0xffe) { |
3645 |
|
ic->arg[0] = (size_t) (cpu->cd.sh.cur_ic_page + |
3646 |
|
(ic->arg[0] >> SH_INSTR_ALIGNMENT_SHIFT)); |
3647 |
|
ic->f = samepage_function; |
3648 |
|
} |
3649 |
break; |
break; |
3650 |
|
|
3651 |
case 0xc: |
case 0xc: |
3712 |
ic->f = instr(or_b_imm_r0_gbr); |
ic->f = instr(or_b_imm_r0_gbr); |
3713 |
ic->arg[0] = lo8; |
ic->arg[0] = lo8; |
3714 |
break; |
break; |
3715 |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
default:if (!cpu->translation_readahead) |
3716 |
main_opcode, r8); |
fatal("Unimplemented opcode 0x%x,0x%x\n", |
3717 |
|
main_opcode, r8); |
3718 |
goto bad; |
goto bad; |
3719 |
} |
} |
3720 |
break; |
break; |
3723 |
ic->f = instr(mov_l_disp_pc_rn); |
ic->f = instr(mov_l_disp_pc_rn); |
3724 |
ic->arg[0] = lo8 * 4 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
ic->arg[0] = lo8 * 4 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) |
3725 |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~3) + 4; |
<< SH_INSTR_ALIGNMENT_SHIFT) & ~3) + 4; |
3726 |
|
|
3727 |
|
/* If the word is reachable from the same page as the |
3728 |
|
current address, then optimize it as a mov_imm_rn: */ |
3729 |
|
if (ic->arg[0] < 0x1000 && page != NULL) { |
3730 |
|
uint32_t *p = (uint32_t *) page; |
3731 |
|
uint32_t data = p[ic->arg[0] >> 2]; |
3732 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3733 |
|
data = LE32_TO_HOST(data); |
3734 |
|
else |
3735 |
|
data = BE32_TO_HOST(data); |
3736 |
|
ic->f = instr(mov_imm_rn); |
3737 |
|
ic->arg[0] = data; |
3738 |
|
} |
3739 |
break; |
break; |
3740 |
|
|
3741 |
case 0xe: /* MOV #imm,Rn */ |
case 0xe: /* MOV #imm,Rn */ |
3742 |
ic->f = instr(mov_imm_rn); |
ic->f = instr(mov_imm_rn); |
3743 |
ic->arg[0] = (int8_t)lo8; |
ic->arg[0] = (int8_t)lo8; |
3744 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
3745 |
|
if (lo8 == 0) |
3746 |
|
ic->f = instr(mov_0_rn); |
3747 |
break; |
break; |
3748 |
|
|
3749 |
case 0xf: |
case 0xf: |
3880 |
ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; |
ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; |
3881 |
ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; |
ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; |
3882 |
} else { |
} else { |
3883 |
fatal("Unimplemented opcode 0x%x,0x%02x\n", |
if (!cpu->translation_readahead) |
3884 |
main_opcode, lo8); |
fatal("Unimplemented opcode 0x%x,0x%02x\n", |
3885 |
|
main_opcode, lo8); |
3886 |
goto bad; |
goto bad; |
3887 |
} |
} |
3888 |
break; |
break; |
3889 |
|
|
3890 |
default:fatal("Unimplemented main opcode 0x%x\n", main_opcode); |
default:if (!cpu->translation_readahead) |
3891 |
|
fatal("Unimplemented main opcode 0x%x\n", main_opcode); |
3892 |
goto bad; |
goto bad; |
3893 |
} |
} |
3894 |
|
|