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_sh_instr.c,v 1.44 2006/11/02 05:43:43 debug Exp $ |
* $Id: cpu_sh_instr.c,v 1.51 2007/03/08 19:04:09 debug Exp $ |
29 |
* |
* |
30 |
* SH instructions. |
* SH instructions. |
31 |
* |
* |
196 |
|
|
197 |
|
|
198 |
/* |
/* |
199 |
|
* xor_b_imm_r0_gbr: mem[r0+gbr] |= imm |
200 |
|
* or_b_imm_r0_gbr: mem[r0+gbr] ^= imm |
201 |
|
* and_b_imm_r0_gbr: mem[r0+gbr] &= imm |
202 |
|
* |
203 |
|
* arg[0] = imm |
204 |
|
*/ |
205 |
|
X(xor_b_imm_r0_gbr) |
206 |
|
{ |
207 |
|
uint32_t addr = cpu->cd.sh.gbr + cpu->cd.sh.r[0]; |
208 |
|
uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; |
209 |
|
|
210 |
|
if (p != NULL) { |
211 |
|
p[addr & 0xfff] ^= ic->arg[0]; |
212 |
|
} else { |
213 |
|
uint8_t data; |
214 |
|
SYNCH_PC; |
215 |
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, |
216 |
|
sizeof(data), MEM_READ, CACHE_DATA)) { |
217 |
|
/* Exception. */ |
218 |
|
return; |
219 |
|
} |
220 |
|
data ^= ic->arg[0]; |
221 |
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, |
222 |
|
sizeof(data), MEM_WRITE, CACHE_DATA)) { |
223 |
|
/* Exception. */ |
224 |
|
return; |
225 |
|
} |
226 |
|
} |
227 |
|
} |
228 |
|
X(or_b_imm_r0_gbr) |
229 |
|
{ |
230 |
|
uint32_t addr = cpu->cd.sh.gbr + cpu->cd.sh.r[0]; |
231 |
|
uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; |
232 |
|
|
233 |
|
if (p != NULL) { |
234 |
|
p[addr & 0xfff] |= ic->arg[0]; |
235 |
|
} else { |
236 |
|
uint8_t data; |
237 |
|
SYNCH_PC; |
238 |
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, |
239 |
|
sizeof(data), MEM_READ, CACHE_DATA)) { |
240 |
|
/* Exception. */ |
241 |
|
return; |
242 |
|
} |
243 |
|
data |= ic->arg[0]; |
244 |
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, |
245 |
|
sizeof(data), MEM_WRITE, CACHE_DATA)) { |
246 |
|
/* Exception. */ |
247 |
|
return; |
248 |
|
} |
249 |
|
} |
250 |
|
} |
251 |
|
X(and_b_imm_r0_gbr) |
252 |
|
{ |
253 |
|
uint32_t addr = cpu->cd.sh.gbr + cpu->cd.sh.r[0]; |
254 |
|
uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; |
255 |
|
|
256 |
|
if (p != NULL) { |
257 |
|
p[addr & 0xfff] &= ic->arg[0]; |
258 |
|
} else { |
259 |
|
uint8_t data; |
260 |
|
SYNCH_PC; |
261 |
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, |
262 |
|
sizeof(data), MEM_READ, CACHE_DATA)) { |
263 |
|
/* Exception. */ |
264 |
|
return; |
265 |
|
} |
266 |
|
data &= ic->arg[0]; |
267 |
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, |
268 |
|
sizeof(data), MEM_WRITE, CACHE_DATA)) { |
269 |
|
/* Exception. */ |
270 |
|
return; |
271 |
|
} |
272 |
|
} |
273 |
|
} |
274 |
|
|
275 |
|
|
276 |
|
/* |
277 |
* mov_imm_rn: Set rn to a signed 8-bit value |
* mov_imm_rn: Set rn to a signed 8-bit value |
278 |
* add_imm_rn: Add a signed 8-bit value to Rn |
* add_imm_rn: Add a signed 8-bit value to Rn |
279 |
* |
* |
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]; |
2032 |
cpu->cd.sh.utlb_hi[urc] = cpu->cd.sh.pteh; |
cpu->cd.sh.utlb_hi[urc] = cpu->cd.sh.pteh; |
2033 |
cpu->cd.sh.utlb_lo[urc] = cpu->cd.sh.ptel; |
cpu->cd.sh.utlb_lo[urc] = cpu->cd.sh.ptel; |
2034 |
|
|
2035 |
if ((old_lo & SH4_PTEL_SZ_MASK) == SH4_PTEL_SZ_4K) |
/* Invalidate the old mapping, if it belonged to the same ASID: */ |
2036 |
cpu->invalidate_translation_caches(cpu, |
if ((old_hi & SH4_PTEH_ASID_MASK) == |
2037 |
old_hi & 0xfffff000, INVALIDATE_VADDR); |
(cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { |
2038 |
else |
if ((old_lo & SH4_PTEL_SZ_MASK) == SH4_PTEL_SZ_4K) |
2039 |
cpu->invalidate_translation_caches(cpu, |
cpu->invalidate_translation_caches(cpu, |
2040 |
old_hi & 0xfffff000, INVALIDATE_ALL); |
old_hi & 0xfffff000, INVALIDATE_VADDR); |
2041 |
|
else |
2042 |
|
cpu->invalidate_translation_caches(cpu, |
2043 |
|
old_hi & 0xfffff000, INVALIDATE_ALL); |
2044 |
|
} |
2045 |
} |
} |
2046 |
|
|
2047 |
|
|
2632 |
|
|
2633 |
|
|
2634 |
/* |
/* |
2635 |
* prom_emul_dreamcast: |
* prom_emul: |
2636 |
*/ |
*/ |
2637 |
X(prom_emul_dreamcast) |
X(prom_emul) |
2638 |
{ |
{ |
2639 |
uint32_t old_pc; |
uint32_t old_pc; |
2640 |
SYNCH_PC; |
SYNCH_PC; |
2641 |
old_pc = cpu->pc; |
old_pc = cpu->pc; |
2642 |
|
|
2643 |
dreamcast_emul(cpu); |
switch (cpu->machine->machine_type) { |
2644 |
|
case MACHINE_DREAMCAST: |
2645 |
|
dreamcast_emul(cpu); |
2646 |
|
break; |
2647 |
|
case MACHINE_LANDISK: |
2648 |
|
sh_ipl_g_emul(cpu); |
2649 |
|
break; |
2650 |
|
default: |
2651 |
|
fatal("SH prom_emul: unimplemented machine type.\n"); |
2652 |
|
exit(1); |
2653 |
|
} |
2654 |
|
|
2655 |
if (!cpu->running) { |
if (!cpu->running) { |
2656 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
2900 |
/* STC Rm_BANK, Rn */ |
/* STC Rm_BANK, Rn */ |
2901 |
ic->f = instr(copy_privileged_register); |
ic->f = instr(copy_privileged_register); |
2902 |
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]; |
2903 |
} else if (iword == 0x00ff) { |
} else if (iword == SH_INVALID_INSTR) { |
2904 |
/* PROM emulation specifically for Dreamcast */ |
/* PROM emulation (GXemul specific) */ |
2905 |
ic->f = instr(prom_emul_dreamcast); |
ic->f = instr(prom_emul); |
2906 |
} else { |
} else { |
2907 |
switch (lo8) { |
switch (lo8) { |
2908 |
case 0x02: /* STC SR,Rn */ |
case 0x02: /* STC SR,Rn */ |
3112 |
ic->f = instr(shld); |
ic->f = instr(shld); |
3113 |
} else if ((lo8 & 0x8f) == 0x83) { |
} else if ((lo8 & 0x8f) == 0x83) { |
3114 |
/* STC.L Rm_BANK,@-Rn */ |
/* STC.L Rm_BANK,@-Rn */ |
3115 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3116 |
ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[ |
ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[ |
3117 |
(lo8 >> 4) & 7]; /* m */ |
(lo8 >> 4) & 7]; /* m */ |
3118 |
} else if ((lo8 & 0x8f) == 0x87) { |
} else if ((lo8 & 0x8f) == 0x87) { |
3137 |
ic->arg[0] = (size_t)&cpu->cd.sh.mach; |
ic->arg[0] = (size_t)&cpu->cd.sh.mach; |
3138 |
break; |
break; |
3139 |
case 0x03: /* STC.L SR,@-Rn */ |
case 0x03: /* STC.L SR,@-Rn */ |
3140 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3141 |
ic->arg[0] = (size_t)&cpu->cd.sh.sr; |
ic->arg[0] = (size_t)&cpu->cd.sh.sr; |
3142 |
break; |
break; |
3143 |
case 0x04: /* ROTL Rn */ |
case 0x04: /* ROTL Rn */ |
3182 |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
3183 |
break; |
break; |
3184 |
case 0x13: /* STC.L GBR,@-Rn */ |
case 0x13: /* STC.L GBR,@-Rn */ |
3185 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(mov_l_rm_predec_rn); |
3186 |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
3187 |
break; |
break; |
3188 |
case 0x15: /* CMP/PL Rn */ |
case 0x15: /* CMP/PL Rn */ |
3193 |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
ic->arg[0] = (size_t)&cpu->cd.sh.macl; |
3194 |
break; |
break; |
3195 |
case 0x17: /* LDC.L @Rm+,GBR */ |
case 0x17: /* LDC.L @Rm+,GBR */ |
3196 |
ic->f = instr(mov_l_arg1_postinc_to_arg0_md); |
ic->f = instr(mov_l_arg1_postinc_to_arg0); |
3197 |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.gbr; |
3198 |
break; |
break; |
3199 |
case 0x18: /* SHLL8 Rn */ |
case 0x18: /* SHLL8 Rn */ |
3205 |
case 0x1b: /* TAS.B @Rn */ |
case 0x1b: /* TAS.B @Rn */ |
3206 |
ic->f = instr(tas_b_rn); |
ic->f = instr(tas_b_rn); |
3207 |
break; |
break; |
3208 |
|
case 0x1e: /* LDC Rm,GBR */ |
3209 |
|
ic->f = instr(mov_rm_rn); |
3210 |
|
ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ |
3211 |
|
ic->arg[1] = (size_t)&cpu->cd.sh.gbr; |
3212 |
|
break; |
3213 |
case 0x20: /* SHAL Rn */ |
case 0x20: /* SHAL Rn */ |
3214 |
ic->f = instr(shll_rn); /* NOTE: shll */ |
ic->f = instr(shll_rn); /* NOTE: shll */ |
3215 |
break; |
break; |
3222 |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ |
3223 |
break; |
break; |
3224 |
case 0x23: /* STC.L VBR,@-Rn */ |
case 0x23: /* STC.L VBR,@-Rn */ |
3225 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3226 |
ic->arg[0] = (size_t)&cpu->cd.sh.vbr; |
ic->arg[0] = (size_t)&cpu->cd.sh.vbr; |
3227 |
break; |
break; |
3228 |
case 0x24: /* ROTCL Rn */ |
case 0x24: /* ROTCL Rn */ |
3264 |
ic->arg[1] = (size_t)&cpu->cd.sh.vbr; |
ic->arg[1] = (size_t)&cpu->cd.sh.vbr; |
3265 |
break; |
break; |
3266 |
case 0x33: /* STC.L SSR,@-Rn */ |
case 0x33: /* STC.L SSR,@-Rn */ |
3267 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3268 |
ic->arg[0] = (size_t)&cpu->cd.sh.ssr; |
ic->arg[0] = (size_t)&cpu->cd.sh.ssr; |
3269 |
break; |
break; |
3270 |
case 0x37: /* LDC.L @Rm+,SSR */ |
case 0x37: /* LDC.L @Rm+,SSR */ |
3277 |
ic->arg[1] = (size_t)&cpu->cd.sh.ssr; |
ic->arg[1] = (size_t)&cpu->cd.sh.ssr; |
3278 |
break; |
break; |
3279 |
case 0x43: /* STC.L SPC,@-Rn */ |
case 0x43: /* STC.L SPC,@-Rn */ |
3280 |
ic->f = instr(stc_l_rm_predec_rn); |
ic->f = instr(stc_l_rm_predec_rn_md); |
3281 |
ic->arg[0] = (size_t)&cpu->cd.sh.spc; |
ic->arg[0] = (size_t)&cpu->cd.sh.spc; |
3282 |
break; |
break; |
3283 |
case 0x47: /* LDC.L @Rm+,SPC */ |
case 0x47: /* LDC.L @Rm+,SPC */ |
3519 |
ic->f = instr(or_imm_r0); |
ic->f = instr(or_imm_r0); |
3520 |
ic->arg[0] = lo8; |
ic->arg[0] = lo8; |
3521 |
break; |
break; |
3522 |
|
case 0xd: /* AND.B #imm,@(R0,GBR) */ |
3523 |
|
ic->f = instr(and_b_imm_r0_gbr); |
3524 |
|
ic->arg[0] = lo8; |
3525 |
|
break; |
3526 |
|
case 0xe: /* XOR.B #imm,@(R0,GBR) */ |
3527 |
|
ic->f = instr(xor_b_imm_r0_gbr); |
3528 |
|
ic->arg[0] = lo8; |
3529 |
|
break; |
3530 |
|
case 0xf: /* OR.B #imm,@(R0,GBR) */ |
3531 |
|
ic->f = instr(or_b_imm_r0_gbr); |
3532 |
|
ic->arg[0] = lo8; |
3533 |
|
break; |
3534 |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
default:fatal("Unimplemented opcode 0x%x,0x%x\n", |
3535 |
main_opcode, r8); |
main_opcode, r8); |
3536 |
goto bad; |
goto bad; |