bugfixes related to mmap usage for ROM
[picodrive.git] / pico / sek.c
CommitLineData
cc68a136 1// This is part of Pico Library\r
2\r
3// (c) Copyright 2004 Dave, All rights reserved.\r
4// (c) Copyright 2006 notaz, All rights reserved.\r
5// Free for non-commercial use.\r
6\r
7// For commercial use, separate licencing terms must be obtained.\r
8\r
9\r
efcba75f 10#include "pico_int.h"\r
488c0bbf 11#include "memory.h"\r
cc68a136 12\r
13\r
14int SekCycleCnt=0; // cycles done in this frame\r
15int SekCycleAim=0; // cycle aim\r
16unsigned int SekCycleCntT=0;\r
17\r
70357ce5 18\r
19/* context */\r
20// Cyclone 68000\r
cc68a136 21#ifdef EMU_C68K\r
3aa1e148 22struct Cyclone PicoCpuCM68k;\r
cc68a136 23#endif\r
70357ce5 24// MUSASHI 68000\r
cc68a136 25#ifdef EMU_M68K\r
3aa1e148 26m68ki_cpu_core PicoCpuMM68k;\r
cc68a136 27#endif\r
70357ce5 28// FAME 68000\r
29#ifdef EMU_F68K\r
3aa1e148 30M68K_CONTEXT PicoCpuFM68k;\r
cc68a136 31#endif\r
32\r
33\r
70357ce5 34/* callbacks */\r
cc68a136 35#ifdef EMU_C68K\r
b837b69b 36// interrupt acknowledgment\r
0af33fe0 37static int SekIntAck(int level)\r
cc68a136 38{\r
39 // try to emulate VDP's reaction to 68000 int ack\r
69996cb7 40 if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); }\r
41 else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); }\r
3aa1e148 42 PicoCpuCM68k.irq = 0;\r
0af33fe0 43 return CYCLONE_INT_ACK_AUTOVECTOR;\r
cc68a136 44}\r
45\r
69996cb7 46static void SekResetAck(void)\r
cc68a136 47{\r
69996cb7 48 elprintf(EL_ANOMALY, "Reset encountered @ %06x", SekPc);\r
cc68a136 49}\r
50\r
51static int SekUnrecognizedOpcode()\r
52{\r
53 unsigned int pc, op;\r
54 pc = SekPc;\r
3aa1e148 55 op = PicoCpuCM68k.read16(pc);\r
69996cb7 56 elprintf(EL_ANOMALY, "Unrecognized Opcode %04x @ %06x", op, pc);\r
cc68a136 57 // see if we are not executing trash\r
58 if (pc < 0x200 || (pc > Pico.romsize+4 && (pc&0xe00000)!=0xe00000)) {\r
3aa1e148 59 PicoCpuCM68k.cycles = 0;\r
60 PicoCpuCM68k.state_flags |= 1;\r
cc68a136 61 return 1;\r
62 }\r
2d0b15bb 63#ifdef EMU_M68K // debugging cyclone\r
64 {\r
65 extern int have_illegal;\r
66 have_illegal = 1;\r
67 }\r
68#endif\r
cc68a136 69 return 0;\r
70}\r
71#endif\r
72\r
73\r
74#ifdef EMU_M68K\r
75static int SekIntAckM68K(int level)\r
76{\r
69996cb7 77 if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); }\r
78 else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); }\r
cc68a136 79 CPU_INT_LEVEL = 0;\r
80 return M68K_INT_ACK_AUTOVECTOR;\r
81}\r
0af33fe0 82\r
83static int SekTasCallback(void)\r
84{\r
85 return 0; // no writeback\r
86}\r
cc68a136 87#endif\r
88\r
89\r
70357ce5 90#ifdef EMU_F68K\r
3aa1e148 91static void SekIntAckF68K(unsigned level)\r
70357ce5 92{\r
93 if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); }\r
94 else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); }\r
3aa1e148 95 PicoCpuFM68k.interrupts[0] = 0;\r
70357ce5 96}\r
97#endif\r
98\r
cc68a136 99\r
2aa27095 100PICO_INTERNAL void SekInit(void)\r
cc68a136 101{\r
102#ifdef EMU_C68K\r
103 CycloneInit();\r
3aa1e148 104 memset(&PicoCpuCM68k,0,sizeof(PicoCpuCM68k));\r
105 PicoCpuCM68k.IrqCallback=SekIntAck;\r
106 PicoCpuCM68k.ResetCallback=SekResetAck;\r
107 PicoCpuCM68k.UnrecognizedCallback=SekUnrecognizedOpcode;\r
03e4f2a3 108 PicoCpuCM68k.flags=4; // Z set\r
cc68a136 109#endif\r
cc68a136 110#ifdef EMU_M68K\r
111 {\r
112 void *oldcontext = m68ki_cpu_p;\r
3aa1e148 113 m68k_set_context(&PicoCpuMM68k);\r
cc68a136 114 m68k_set_cpu_type(M68K_CPU_TYPE_68000);\r
115 m68k_init();\r
116 m68k_set_int_ack_callback(SekIntAckM68K);\r
0af33fe0 117 m68k_set_tas_instr_callback(SekTasCallback);\r
9037e45d 118 //m68k_pulse_reset();\r
cc68a136 119 m68k_set_context(oldcontext);\r
120 }\r
121#endif\r
70357ce5 122#ifdef EMU_F68K\r
123 {\r
124 void *oldcontext = g_m68kcontext;\r
3aa1e148 125 g_m68kcontext = &PicoCpuFM68k;\r
126 memset(&PicoCpuFM68k, 0, sizeof(PicoCpuFM68k));\r
03e4f2a3 127 fm68k_init();\r
3aa1e148 128 PicoCpuFM68k.iack_handler = SekIntAckF68K;\r
b5e5172d 129 PicoCpuFM68k.sr = 0x2704; // Z flag\r
70357ce5 130 g_m68kcontext = oldcontext;\r
131 }\r
132#endif\r
cc68a136 133}\r
134\r
70357ce5 135\r
cc68a136 136// Reset the 68000:\r
2aa27095 137PICO_INTERNAL int SekReset(void)\r
cc68a136 138{\r
139 if (Pico.rom==NULL) return 1;\r
140\r
141#ifdef EMU_C68K\r
5e89f0f5 142 CycloneReset(&PicoCpuCM68k);\r
cc68a136 143#endif\r
cc68a136 144#ifdef EMU_M68K\r
3aa1e148 145 m68k_set_context(&PicoCpuMM68k); // if we ever reset m68k, we always need it's context to be set\r
2d0b15bb 146 m68ki_cpu.sp[0]=0;\r
147 m68k_set_irq(0);\r
b837b69b 148 m68k_pulse_reset();\r
99464b62 149 REG_USP = 0; // ?\r
cc68a136 150#endif\r
70357ce5 151#ifdef EMU_F68K\r
152 {\r
3aa1e148 153 g_m68kcontext = &PicoCpuFM68k;\r
03e4f2a3 154 fm68k_reset();\r
70357ce5 155 }\r
156#endif\r
cc68a136 157\r
158 return 0;\r
159}\r
160\r
5f9a0d16 161void SekStepM68k(void)\r
162{\r
163 SekCycleAim=SekCycleCnt+1;\r
164#if defined(EMU_CORE_DEBUG)\r
165 SekCycleCnt+=CM_compareRun(1, 0);\r
166#elif defined(EMU_C68K)\r
167 PicoCpuCM68k.cycles=1;\r
168 CycloneRun(&PicoCpuCM68k);\r
169 SekCycleCnt+=1-PicoCpuCM68k.cycles;\r
170#elif defined(EMU_M68K)\r
171 SekCycleCnt+=m68k_execute(1);\r
172#elif defined(EMU_F68K)\r
f579f7b8 173 SekCycleCnt+=fm68k_emulate(1, 0, 0);\r
5f9a0d16 174#endif\r
175}\r
cc68a136 176\r
eff55556 177PICO_INTERNAL void SekSetRealTAS(int use_real)\r
2433f409 178{\r
179#ifdef EMU_C68K\r
180 CycloneSetRealTAS(use_real);\r
181#endif\r
70357ce5 182#ifdef EMU_F68K\r
183 // TODO\r
184#endif\r
2433f409 185}\r
186\r
5f9a0d16 187\r
053fd9b4 188/* idle loop detection, not to be used in CD mode */\r
189#ifdef EMU_C68K\r
190#include "cpu/Cyclone/tools/idle.h"\r
191#endif\r
192\r
488c0bbf 193static unsigned short **idledet_ptrs = NULL;\r
053fd9b4 194static int idledet_count = 0, idledet_bads = 0;\r
195int idledet_start_frame = 0;\r
053fd9b4 196\r
5ed2a20e 197#if 0\r
198#define IDLE_STATS 1\r
199unsigned int idlehit_addrs[128], idlehit_counts[128];\r
200\r
201void SekRegisterIdleHit(unsigned int pc)\r
202{\r
203 int i;\r
204 for (i = 0; i < 127 && idlehit_addrs[i]; i++) {\r
205 if (idlehit_addrs[i] == pc) {\r
206 idlehit_counts[i]++;\r
207 return;\r
208 }\r
209 }\r
210 idlehit_addrs[i] = pc;\r
211 idlehit_counts[i] = 1;\r
212 idlehit_addrs[i+1] = 0;\r
213}\r
214#endif\r
215\r
053fd9b4 216void SekInitIdleDet(void)\r
217{\r
488c0bbf 218 unsigned short **tmp = realloc(idledet_ptrs, 0x200*4);\r
053fd9b4 219 if (tmp == NULL) {\r
488c0bbf 220 free(idledet_ptrs);\r
221 idledet_ptrs = NULL;\r
053fd9b4 222 }\r
223 else\r
488c0bbf 224 idledet_ptrs = tmp;\r
053fd9b4 225 idledet_count = idledet_bads = 0;\r
226 idledet_start_frame = Pico.m.frame_count + 360;\r
5ed2a20e 227#ifdef IDLE_STATS\r
228 idlehit_addrs[0] = 0;\r
229#endif\r
053fd9b4 230\r
053fd9b4 231#ifdef EMU_C68K\r
232 CycloneInitIdle();\r
233#endif\r
c060a9ab 234#ifdef EMU_F68K\r
c060a9ab 235 fm68k_emulate(0, 0, 1);\r
236#endif\r
053fd9b4 237}\r
238\r
239int SekIsIdleCode(unsigned short *dst, int bytes)\r
240{\r
8187ba84 241 // printf("SekIsIdleCode %04x %i\n", *dst, bytes);\r
053fd9b4 242 switch (bytes)\r
243 {\r
5ed2a20e 244 case 2:\r
245 if ((*dst & 0xf000) != 0x6000) // not another branch\r
246 return 1;\r
247 break;\r
053fd9b4 248 case 4:\r
b0677887 249 if ( (*dst & 0xfff8) == 0x4a10 || // tst.b ($aX) // there should be no need to wait\r
250 (*dst & 0xfff8) == 0x4a28 || // tst.b ($xxxx,a0) // for byte change anywhere\r
251 (*dst & 0xff3f) == 0x4a38 || // tst.x ($xxxx.w); tas ($xxxx.w)\r
053fd9b4 252 (*dst & 0xc1ff) == 0x0038 || // move.x ($xxxx.w), dX\r
253 (*dst & 0xf13f) == 0xb038) // cmp.x ($xxxx.w), dX\r
254 return 1;\r
255 break;\r
256 case 6:\r
b0677887 257 if ( ((dst[1] & 0xe0) == 0xe0 && ( // RAM and\r
258 *dst == 0x4a39 || // tst.b ($xxxxxxxx)\r
259 *dst == 0x4a79 || // tst.w ($xxxxxxxx)\r
260 *dst == 0x4ab9 || // tst.l ($xxxxxxxx)\r
261 (*dst & 0xc1ff) == 0x0039 || // move.x ($xxxxxxxx), dX\r
262 (*dst & 0xf13f) == 0xb039))||// cmp.x ($xxxxxxxx), dX\r
263 *dst == 0x0838 || // btst $X, ($xxxx.w) [6 byte op]\r
264 (*dst & 0xffbf) == 0x0c38) // cmpi.{b,w} $X, ($xxxx.w)\r
053fd9b4 265 return 1;\r
266 break;\r
267 case 8:\r
b0677887 268 if ( ((dst[2] & 0xe0) == 0xe0 && ( // RAM and\r
269 *dst == 0x0839 || // btst $X, ($xxxxxxxx.w) [8 byte op]\r
270 (*dst & 0xffbf) == 0x0c39))||// cmpi.{b,w} $X, ($xxxxxxxx)\r
271 *dst == 0x0cb8) // cmpi.l $X, ($xxxx.w)\r
053fd9b4 272 return 1;\r
273 break;\r
274 case 12:\r
275 if ((*dst & 0xf1f8) == 0x3010 && // move.w (aX), dX\r
b0677887 276 (dst[1]&0xf100) == 0x0000 && // arithmetic\r
277 (dst[3]&0xf100) == 0x0000) // arithmetic\r
053fd9b4 278 return 1;\r
279 break;\r
280 }\r
281\r
282 return 0;\r
283}\r
284\r
5ed2a20e 285int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop, void *ctx)\r
053fd9b4 286{\r
5ed2a20e 287 int is_main68k = 1;\r
488c0bbf 288 u16 *target;\r
289 uptr v;\r
290\r
5ed2a20e 291#if defined(EMU_C68K)\r
292 struct Cyclone *cyc = ctx;\r
293 is_main68k = cyc == &PicoCpuCM68k;\r
294 pc -= cyc->membase;\r
295#elif defined(EMU_F68K)\r
296 is_main68k = ctx == &PicoCpuFM68k;\r
053fd9b4 297#endif\r
298 pc &= ~0xff000000;\r
5ed2a20e 299 elprintf(EL_IDLE, "idle: patch %06x %04x %04x %c %c #%i", pc, oldop, newop,\r
300 (newop&0x200)?'n':'y', is_main68k?'m':'s', idledet_count);\r
301\r
488c0bbf 302 // XXX: probably shouldn't patch RAM too\r
303 v = m68k_read16_map[pc >> M68K_MEM_SHIFT];\r
304 if (!(v & 0x80000000))\r
305 target = (u16 *)((v << 1) + pc);\r
306 else {\r
307 if (++idledet_bads > 128)\r
308 return 2; // remove detector\r
053fd9b4 309 return 1; // don't patch\r
310 }\r
311\r
312 if (idledet_count >= 0x200 && (idledet_count & 0x1ff) == 0) {\r
488c0bbf 313 unsigned short **tmp = realloc(idledet_ptrs, (idledet_count+0x200)*4);\r
314 if (tmp == NULL)\r
315 return 1;\r
316 idledet_ptrs = tmp;\r
053fd9b4 317 }\r
318\r
488c0bbf 319 idledet_ptrs[idledet_count++] = target;\r
b0677887 320\r
053fd9b4 321 return 0;\r
322}\r
323\r
324void SekFinishIdleDet(void)\r
325{\r
053fd9b4 326#ifdef EMU_C68K\r
327 CycloneFinishIdle();\r
c060a9ab 328#endif\r
329#ifdef EMU_F68K\r
330 fm68k_emulate(0, 0, 2);\r
053fd9b4 331#endif\r
332 while (idledet_count > 0)\r
333 {\r
488c0bbf 334 unsigned short *op = idledet_ptrs[--idledet_count];\r
053fd9b4 335 if ((*op & 0xfd00) == 0x7100)\r
336 *op &= 0xff, *op |= 0x6600;\r
337 else if ((*op & 0xfd00) == 0x7500)\r
338 *op &= 0xff, *op |= 0x6700;\r
339 else if ((*op & 0xfd00) == 0x7d00)\r
340 *op &= 0xff, *op |= 0x6000;\r
341 else\r
342 elprintf(EL_STATUS|EL_IDLE, "idle: don't know how to restore %04x", *op);\r
343 }\r
053fd9b4 344}\r
345\r
346\r
6cab49fd 347#if defined(EMU_M68K) && M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER\r
348static unsigned char op_flags[0x400000/2] = { 0, };\r
349static int atexit_set = 0;\r
350\r
351static void make_idc(void)\r
352{\r
353 FILE *f = fopen("idc.idc", "w");\r
354 int i;\r
355 if (!f) return;\r
356 fprintf(f, "#include <idc.idc>\nstatic main() {\n");\r
357 for (i = 0; i < 0x400000/2; i++)\r
358 if (op_flags[i] != 0)\r
359 fprintf(f, " MakeCode(0x%06x);\n", i*2);\r
360 fprintf(f, "}\n");\r
361 fclose(f);\r
362}\r
363\r
364void instruction_hook(void)\r
365{\r
366 if (!atexit_set) {\r
367 atexit(make_idc);\r
368 atexit_set = 1;\r
369 }\r
370 if (REG_PC < 0x400000)\r
371 op_flags[REG_PC/2] = 1;\r
372}\r
373#endif\r