25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_sh_instr.c,v 1.49 2007/01/28 16:59:06 debug Exp $ |
* $Id: cpu_sh_instr.c,v 1.56 2007/04/19 15:49:39 debug Exp $ |
29 |
* |
* |
30 |
* SH instructions. |
* SH instructions. |
31 |
* |
* |
285 |
|
|
286 |
|
|
287 |
/* |
/* |
288 |
* mov_b_rm_predec_rn: mov.b reg,@-Rn |
* mov_b_rm_predec_rn: mov.b reg,@-Rn |
289 |
* mov_w_rm_predec_rn: mov.w reg,@-Rn |
* mov_w_rm_predec_rn: mov.w reg,@-Rn |
290 |
* mov_l_rm_predec_rn: mov.l reg,@-Rn |
* mov_l_rm_predec_rn: mov.l reg,@-Rn |
291 |
* stc_l_rm_predec_rn: mov.l reg,@-Rn, with MD status bit check |
* stc_l_rm_predec_rn_md: mov.l reg,@-Rn, with MD status bit check |
292 |
* |
* |
293 |
* arg[0] = ptr to rm (or other register) |
* arg[0] = ptr to rm (or other register) |
294 |
* arg[1] = ptr to rn |
* arg[1] = ptr to rn |
362 |
reg(ic->arg[1]) = addr; |
reg(ic->arg[1]) = addr; |
363 |
} |
} |
364 |
} |
} |
365 |
X(stc_l_rm_predec_rn) |
X(stc_l_rm_predec_rn_md) |
366 |
{ |
{ |
367 |
uint32_t addr = reg(ic->arg[1]) - sizeof(uint32_t); |
uint32_t addr = reg(ic->arg[1]) - sizeof(uint32_t); |
368 |
uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; |
uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; |
818 |
else |
else |
819 |
data = BE32_TO_HOST(data); |
data = BE32_TO_HOST(data); |
820 |
reg(ic->arg[1]) = addr + sizeof(data); |
reg(ic->arg[1]) = addr + sizeof(data); |
821 |
reg(ic->arg[0]) = data; |
|
822 |
|
/* Special case when loading into the SR register: */ |
823 |
|
if (ic->arg[0] == (size_t)&cpu->cd.sh.sr) |
824 |
|
sh_update_sr(cpu, data); |
825 |
|
else |
826 |
|
reg(ic->arg[0]) = data; |
827 |
} |
} |
828 |
X(mov_l_arg1_postinc_to_arg0_fp) |
X(mov_l_arg1_postinc_to_arg0_fp) |
829 |
{ |
{ |
850 |
data = BE32_TO_HOST(data); |
data = BE32_TO_HOST(data); |
851 |
reg(ic->arg[1]) = addr + sizeof(data); |
reg(ic->arg[1]) = addr + sizeof(data); |
852 |
|
|
853 |
if (ic->arg[0] == (size_t)cpu->cd.sh.fpscr) |
/* Ugly special case for FPSCR: */ |
854 |
|
if (ic->arg[0] == (size_t)&cpu->cd.sh.fpscr) |
855 |
sh_update_fpscr(cpu, data); |
sh_update_fpscr(cpu, data); |
856 |
else |
else |
857 |
reg(ic->arg[0]) = data; |
reg(ic->arg[0]) = data; |
1990 |
|
|
1991 |
|
|
1992 |
/* |
/* |
|
* sts_mach_rn: Store MACH into Rn |
|
|
* sts_macl_rn: Store MACL into Rn |
|
|
* sts_pr_rn: Store PR into Rn |
|
|
* |
|
|
* arg[1] = ptr to rn |
|
|
*/ |
|
|
X(sts_mach_rn) { reg(ic->arg[1]) = cpu->cd.sh.mach; } |
|
|
X(sts_macl_rn) { reg(ic->arg[1]) = cpu->cd.sh.macl; } |
|
|
X(sts_pr_rn) { reg(ic->arg[1]) = cpu->cd.sh.pr; } |
|
|
|
|
|
|
|
|
/* |
|
1993 |
* rte: Return from exception. |
* rte: Return from exception. |
1994 |
*/ |
*/ |
1995 |
X(rte) |
X(rte) |
2034 |
old_hi & 0xfffff000, INVALIDATE_VADDR); |
old_hi & 0xfffff000, INVALIDATE_VADDR); |
2035 |
else |
else |
2036 |
cpu->invalidate_translation_caches(cpu, |
cpu->invalidate_translation_caches(cpu, |
2037 |
old_hi & 0xfffff000, INVALIDATE_ALL); |
0, INVALIDATE_ALL); |
2038 |
} |
} |
2039 |
} |
} |
2040 |
|
|
2062 |
{ |
{ |
2063 |
RES_INST_IF_NOT_MD; |
RES_INST_IF_NOT_MD; |
2064 |
sh_update_sr(cpu, reg(ic->arg[1])); |
sh_update_sr(cpu, reg(ic->arg[1])); |
2065 |
|
|
2066 |
|
#if 0 |
2067 |
|
/* NOTE: This code causes NetBSD/landisk to get past a point where it |
2068 |
|
otherwise hangs, but it causes Linux/Dreamcast to bug out instead. :/ */ |
2069 |
|
|
2070 |
|
if (!(cpu->cd.sh.sr & SH_SR_BL) && cpu->cd.sh.int_to_assert > 0 && |
2071 |
|
( (cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT) |
2072 |
|
< cpu->cd.sh.int_level) { |
2073 |
|
/* Cause interrupt immediately, by dropping out of the |
2074 |
|
main dyntrans loop: */ |
2075 |
|
cpu->cd.sh.next_ic = ¬hing_call; |
2076 |
|
} |
2077 |
|
#endif |
2078 |
} |
} |
2079 |
|
|
2080 |
|
|
2199 |
|
|
2200 |
|
|
2201 |
/* |
/* |
2202 |
|
* fcnvsd_fpul_drn: Convert single-precision to double-precision. |
2203 |
|
* fcnvds_drm_fpul: Convert double-precision to single-precision. |
2204 |
|
* |
2205 |
|
* arg[0] = ptr to destination (double- or single-precision float) |
2206 |
|
*/ |
2207 |
|
X(fcnvsd_fpul_drn) |
2208 |
|
{ |
2209 |
|
struct ieee_float_value op1; |
2210 |
|
int64_t ieee; |
2211 |
|
|
2212 |
|
FLOATING_POINT_AVAILABLE_CHECK; |
2213 |
|
|
2214 |
|
ieee_interpret_float_value(cpu->cd.sh.fpul, &op1, IEEE_FMT_S); |
2215 |
|
cpu->cd.sh.fpul = (int32_t) op1.f; |
2216 |
|
|
2217 |
|
/* Store double-precision result: */ |
2218 |
|
ieee = ieee_store_float_value(op1.f, IEEE_FMT_D, 0); |
2219 |
|
reg(ic->arg[0]) = (uint32_t) (ieee >> 32); |
2220 |
|
reg(ic->arg[0] + sizeof(uint32_t)) = (uint32_t) ieee; |
2221 |
|
} |
2222 |
|
X(fcnvds_drm_fpul) |
2223 |
|
{ |
2224 |
|
struct ieee_float_value op1; |
2225 |
|
int64_t r1; |
2226 |
|
|
2227 |
|
FLOATING_POINT_AVAILABLE_CHECK; |
2228 |
|
|
2229 |
|
r1 = reg(ic->arg[0] + sizeof(uint32_t)) + |
2230 |
|
((uint64_t)reg(ic->arg[0]) << 32); |
2231 |
|
ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); |
2232 |
|
|
2233 |
|
cpu->cd.sh.fpul = ieee_store_float_value(op1.f, IEEE_FMT_S, 0); |
2234 |
|
} |
2235 |
|
|
2236 |
|
|
2237 |
|
/* |
2238 |
* fsca_fpul_drn: Sinus/cosinus approximation. |
* fsca_fpul_drn: Sinus/cosinus approximation. |
2239 |
* |
* |
2240 |
* Note: This is an interesting instruction. It is not included in the SH4 |
* Note: This is an interesting instruction. It is not included in the SH4 |
2675 |
|
|
2676 |
|
|
2677 |
/* |
/* |
2678 |
* prom_emul_dreamcast: |
* prom_emul: |
2679 |
*/ |
*/ |
2680 |
X(prom_emul_dreamcast) |
X(prom_emul) |
2681 |
{ |
{ |
2682 |
uint32_t old_pc; |
uint32_t old_pc; |
2683 |
SYNCH_PC; |
SYNCH_PC; |
2684 |
old_pc = cpu->pc; |
old_pc = cpu->pc; |
2685 |
|
|
2686 |
dreamcast_emul(cpu); |
switch (cpu->machine->machine_type) { |
2687 |
|
case MACHINE_DREAMCAST: |
2688 |
|
dreamcast_emul(cpu); |
2689 |
|
break; |
2690 |
|
case MACHINE_LANDISK: |
2691 |
|
sh_ipl_g_emul(cpu); |
2692 |
|
break; |
2693 |
|
default: |
2694 |
|
fatal("SH prom_emul: unimplemented machine type.\n"); |
2695 |
|
exit(1); |
2696 |
|
} |
2697 |
|
|
2698 |
if (!cpu->running) { |
if (!cpu->running) { |
2699 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
2944 |
ic->f = instr(copy_privileged_register); |
ic->f = instr(copy_privileged_register); |
2945 |
ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[(lo8 >> 4) & 7]; |
ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[(lo8 >> 4) & 7]; |
2946 |
} else if (iword == SH_INVALID_INSTR) { |
} else if (iword == SH_INVALID_INSTR) { |
2947 |
/* PROM emulation specifically for Dreamcast */ |
/* PROM emulation (GXemul specific) */ |
2948 |
ic->f = instr(prom_emul_dreamcast); |
ic->f = instr(prom_emul); |
2949 |
} else { |
} else { |
2950 |
switch (lo8) { |
switch (lo8) { |
2951 |
case 0x02: /* STC SR,Rn */ |
case 0x02: /* STC SR,Rn */ |
2967 |
} |
} |
2968 |
break; |
break; |
2969 |
case 0x0a: /* STS MACH,Rn */ |
case 0x0a: /* STS MACH,Rn */ |
2970 |
ic->f = instr(sts_mach_rn); |
ic->f = instr(mov_rm_rn); |
2971 |
|
ic->arg[0] = (size_t)&cpu->cd.sh.mach; |
2972 |
break; |
break; |
2973 |
case 0x12: /* STC GBR,Rn */ |
case 0x12: /* STC GBR,Rn */ |
2974 |
ic->f = instr(mov_rm_rn); |
ic->f = instr(mov_rm_rn); |
2975 |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
2976 |
break; |
break; |
2977 |
case 0x1a: /* STS MACL,Rn */ |
case 0x1a: /* STS MACL,Rn */ |
2978 |
ic->f = instr(sts_macl_rn); |
ic->f = instr(mov_rm_rn); |
2979 |
|
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
2980 |
break; |
break; |
2981 |
case 0x22: /* STC VBR,Rn */ |
case 0x22: /* STC VBR,Rn */ |
2982 |
ic->f = instr(copy_privileged_register); |
ic->f = instr(copy_privileged_register); |
2993 |
ic->f = instr(movt_rn); |
ic->f = instr(movt_rn); |
2994 |
break; |
break; |
2995 |
case 0x2a: /* STS PR,Rn */ |
case 0x2a: /* STS PR,Rn */ |
2996 |
ic->f = instr(sts_pr_rn); |
ic->f = instr(mov_rm_rn); |
2997 |
|
ic->arg[0] = (size_t)&cpu->cd.sh.pr; |
2998 |
break; |
break; |
2999 |
case 0x32: /* STC SSR,Rn */ |
case 0x32: /* STC SSR,Rn */ |
3000 |
ic->f = instr(copy_privileged_register); |
ic->f = instr(copy_privileged_register); |
3158 |
ic->f = instr(shld); |
ic->f = instr(shld); |
3159 |
} else if ((lo8 & 0x8f) == 0x83) { |
} else if ((lo8 & 0x8f) == 0x83) { |
3160 |
/* STC.L Rm_BANK,@-Rn */ |
/* STC.L Rm_BANK,@-Rn */ |
3161 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3162 |
ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[ |
ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[ |
3163 |
(lo8 >> 4) & 7]; /* m */ |
(lo8 >> 4) & 7]; /* m */ |
3164 |
} else if ((lo8 & 0x8f) == 0x87) { |
} else if ((lo8 & 0x8f) == 0x87) { |
3183 |
ic->arg[0] = (size_t)&cpu->cd.sh.mach; |
ic->arg[0] = (size_t)&cpu->cd.sh.mach; |
3184 |
break; |
break; |
3185 |
case 0x03: /* STC.L SR,@-Rn */ |
case 0x03: /* STC.L SR,@-Rn */ |
3186 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3187 |
ic->arg[0] = (size_t)&cpu->cd.sh.sr; |
ic->arg[0] = (size_t)&cpu->cd.sh.sr; |
3188 |
break; |
break; |
3189 |
case 0x04: /* ROTL Rn */ |
case 0x04: /* ROTL Rn */ |
3228 |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
3229 |
break; |
break; |
3230 |
case 0x13: /* STC.L GBR,@-Rn */ |
case 0x13: /* STC.L GBR,@-Rn */ |
3231 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(mov_l_rm_predec_rn); |
3232 |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
3233 |
break; |
break; |
3234 |
case 0x15: /* CMP/PL Rn */ |
case 0x15: /* CMP/PL Rn */ |
3239 |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
3240 |
break; |
break; |
3241 |
case 0x17: /* LDC.L @Rm+,GBR */ |
case 0x17: /* LDC.L @Rm+,GBR */ |
3242 |
ic->f = instr(mov_l_arg1_postinc_to_arg0_md); |
ic->f = instr(mov_l_arg1_postinc_to_arg0); |
3243 |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
3244 |
break; |
break; |
3245 |
case 0x18: /* SHLL8 Rn */ |
case 0x18: /* SHLL8 Rn */ |
3268 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
3269 |
break; |
break; |
3270 |
case 0x23: /* STC.L VBR,@-Rn */ |
case 0x23: /* STC.L VBR,@-Rn */ |
3271 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3272 |
ic->arg[0] = (size_t)&cpu->cd.sh.vbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.vbr; |
3273 |
break; |
break; |
3274 |
case 0x24: /* ROTCL Rn */ |
case 0x24: /* ROTCL Rn */ |
3310 |
ic->arg[1] = (size_t)&cpu->cd.sh.vbr; |
ic->arg[1] = (size_t)&cpu->cd.sh.vbr; |
3311 |
break; |
break; |
3312 |
case 0x33: /* STC.L SSR,@-Rn */ |
case 0x33: /* STC.L SSR,@-Rn */ |
3313 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3314 |
ic->arg[0] = (size_t)&cpu->cd.sh.ssr; |
ic->arg[0] = (size_t)&cpu->cd.sh.ssr; |
3315 |
break; |
break; |
3316 |
case 0x37: /* LDC.L @Rm+,SSR */ |
case 0x37: /* LDC.L @Rm+,SSR */ |
3323 |
ic->arg[1] = (size_t)&cpu->cd.sh.ssr; |
ic->arg[1] = (size_t)&cpu->cd.sh.ssr; |
3324 |
break; |
break; |
3325 |
case 0x43: /* STC.L SPC,@-Rn */ |
case 0x43: /* STC.L SPC,@-Rn */ |
3326 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3327 |
ic->arg[0] = (size_t)&cpu->cd.sh.spc; |
ic->arg[0] = (size_t)&cpu->cd.sh.spc; |
3328 |
break; |
break; |
3329 |
case 0x47: /* LDC.L @Rm+,SPC */ |
case 0x47: /* LDC.L @Rm+,SPC */ |
3355 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
3356 |
break; |
break; |
3357 |
case 0x66: /* LDS.L @Rm+,FPSCR */ |
case 0x66: /* LDS.L @Rm+,FPSCR */ |
3358 |
|
/* Note: Loading into FPSCR is a specia |
3359 |
|
case (need to call sh_update_fpsrc()). */ |
3360 |
ic->f = instr(mov_l_arg1_postinc_to_arg0_fp); |
ic->f = instr(mov_l_arg1_postinc_to_arg0_fp); |
3361 |
ic->arg[0] = (size_t)&cpu->cd.sh.fpscr; |
ic->arg[0] = (size_t)&cpu->cd.sh.fpscr; |
3362 |
break; |
break; |
3703 |
ic->f = instr(fldi_frn); |
ic->f = instr(fldi_frn); |
3704 |
ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; |
ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; |
3705 |
ic->arg[1] = 0x3f800000; |
ic->arg[1] = 0x3f800000; |
3706 |
|
} else if ((iword & 0x01ff) == 0x00ad) { |
3707 |
|
/* FCNVSD FPUL,DRn */ |
3708 |
|
ic->f = instr(fcnvsd_fpul_drn); |
3709 |
|
ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; |
3710 |
|
} else if ((iword & 0x01ff) == 0x00bd) { |
3711 |
|
/* FCNVDS DRm,FPUL */ |
3712 |
|
ic->f = instr(fcnvds_drm_fpul); |
3713 |
|
ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; |
3714 |
} else if ((iword & 0x01ff) == 0x00fd) { |
} else if ((iword & 0x01ff) == 0x00fd) { |
3715 |
/* FSCA FPUL,DRn */ |
/* FSCA FPUL,DRn */ |
3716 |
ic->f = instr(fsca_fpul_drn); |
ic->f = instr(fsca_fpul_drn); |