optimizations, bugfixes, uae works (but with timing glitches?)
[picodrive.git] / cpu / Cyclone / Ea.cpp
CommitLineData
cc68a136 1\r
2#include "app.h"\r
3\r
4// some ops use non-standard cycle counts for EAs, so are listed here.\r
5// all constants borrowed from the MUSASHI core by Karl Stenerud.\r
6\r
7/* Extra cycles for JMP instruction (000, 010) */\r
8int g_jmp_cycle_table[8] =\r
9{\r
10 4, /* EA_MODE_AI */\r
11 6, /* EA_MODE_DI */\r
12 10, /* EA_MODE_IX */\r
13 6, /* EA_MODE_AW */\r
14 8, /* EA_MODE_AL */\r
15 6, /* EA_MODE_PCDI */\r
16 10, /* EA_MODE_PCIX */\r
17 0, /* EA_MODE_I */\r
18};\r
19\r
20/* Extra cycles for JSR instruction (000, 010) */\r
21int g_jsr_cycle_table[8] =\r
22{\r
23 4, /* EA_MODE_AI */\r
24 6, /* EA_MODE_DI */\r
25 10, /* EA_MODE_IX */\r
26 6, /* EA_MODE_AW */\r
27 8, /* EA_MODE_AL */\r
28 6, /* EA_MODE_PCDI */\r
29 10, /* EA_MODE_PCIX */\r
30 0, /* EA_MODE_I */\r
31};\r
32\r
33/* Extra cycles for LEA instruction (000, 010) */\r
34int g_lea_cycle_table[8] =\r
35{\r
36 4, /* EA_MODE_AI */\r
37 8, /* EA_MODE_DI */\r
38 12, /* EA_MODE_IX */\r
39 8, /* EA_MODE_AW */\r
40 12, /* EA_MODE_AL */\r
41 8, /* EA_MODE_PCDI */\r
42 12, /* EA_MODE_PCIX */\r
43 0, /* EA_MODE_I */\r
44};\r
45\r
46/* Extra cycles for PEA instruction (000, 010) */\r
47int g_pea_cycle_table[8] =\r
48{\r
49 6, /* EA_MODE_AI */\r
50 10, /* EA_MODE_DI */\r
51 14, /* EA_MODE_IX */\r
52 10, /* EA_MODE_AW */\r
53 14, /* EA_MODE_AL */\r
54 10, /* EA_MODE_PCDI */\r
55 14, /* EA_MODE_PCIX */\r
56 0, /* EA_MODE_I */\r
57};\r
58\r
59/* Extra cycles for MOVEM instruction (000, 010) */\r
60int g_movem_cycle_table[8] =\r
61{\r
62 0, /* EA_MODE_AI */\r
63 4, /* EA_MODE_DI */\r
64 6, /* EA_MODE_IX */\r
65 4, /* EA_MODE_AW */\r
66 8, /* EA_MODE_AL */\r
67 0, /* EA_MODE_PCDI */\r
68 0, /* EA_MODE_PCIX */\r
69 0, /* EA_MODE_I */\r
70};\r
71\r
72// add nonstandard EA\r
73int Ea_add_ns(int *tab, int ea)\r
74{\r
a6785576 75 if(ea<0x10) return 0;\r
76 if((ea&0x38)==0x10) return tab[0]; // (An) (ai)\r
77 if(ea<0x28) return 0;\r
78 if(ea<0x30) return tab[1]; // ($nn,An) (di)\r
79 if(ea<0x38) return tab[2]; // ($nn,An,Rn) (ix)\r
80 if(ea==0x38) return tab[3]; // (aw)\r
81 if(ea==0x39) return tab[4]; // (al)\r
82 if(ea==0x3a) return tab[5]; // ($nn,PC) (pcdi)\r
83 if(ea==0x3b) return tab[6]; // ($nn,pc,Rn) (pcix)\r
84 if(ea==0x3c) return tab[7]; // #$nnnn (i)\r
85 return 0;\r
cc68a136 86}\r
87\r
88\r
89// ---------------------------------------------------------------------------\r
90// Gets the offset of a register for an ea, and puts it in 'r'\r
91// Shifted left by 'shift'\r
92// Doesn't trash anything\r
93static int EaCalcReg(int r,int ea,int mask,int forceor,int shift,int noshift=0)\r
94{\r
95 int i=0,low=0,needor=0;\r
96 int lsl=0;\r
97\r
98 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
99 mask&=0xf<<low; // This is the max we can do\r
100\r
03c5768c 101 if (ea>=8)\r
102 {\r
103 needor=1; // Need to OR to access A0-7\r
104 if ((g_op>>low)&8) { needor=0; mask|=8<<low; } // Ah - no we don't actually need to or, since the bit is high in r8\r
105 if (forceor) needor=1; // Special case for 0x30-0x38 EAs ;)\r
106 }\r
cc68a136 107\r
108 ot(" and r%d,r8,#0x%.4x\n",r,mask);\r
109 if (needor) ot(" orr r%d,r%d,#0x%x ;@ A0-7\n",r,r,8<<low);\r
110\r
111 // Find out amount to shift left:\r
112 lsl=shift-low;\r
113\r
114 if (lsl&&!noshift)\r
115 {\r
116 ot(" mov r%d,r%d,",r,r);\r
117 if (lsl>0) ot("lsl #%d\n", lsl);\r
118 else ot("lsr #%d\n",-lsl);\r
119 }\r
120\r
121 return 0;\r
122}\r
123\r
124// EaCalc - ARM Register 'a' = Effective Address\r
85a36a57 125// If ea>=0x10, trashes r0,r2 and r3, else nothing\r
cc68a136 126// size values 0, 1, 2 ~ byte, word, long\r
85a36a57 127// mask shows usable bits in r8\r
b637c56a 128int EaCalc(int a,int mask,int ea,int size,int top,int sign_extend)\r
cc68a136 129{\r
130 char text[32]="";\r
131 int func=0;\r
132\r
133 DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address\r
134 func=0x68+(size<<2); // Get correct read handler\r
135\r
136 if (ea<0x10)\r
137 {\r
138 int noshift=0;\r
b637c56a 139 if (size>=2||(size==0&&(top||!sign_extend))) noshift=1; // Saves one opcode\r
cc68a136 140\r
141 ot(";@ EaCalc : Get register index into r%d:\n",a);\r
142\r
143 EaCalcReg(a,ea,mask,0,2,noshift);\r
144 return 0;\r
145 }\r
146 \r
147 ot(";@ EaCalc : Get '%s' into r%d:\n",text,a);\r
148 // (An), (An)+, -(An)\r
149 if (ea<0x28)\r
150 {\r
151 int step=1<<size, strr=a;\r
a6785576 152 int low=0,lsl,i;\r
cc68a136 153\r
154 if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1\r
155\r
85a36a57 156 if (ea==0x1f||ea==0x27) // A7 handlers are always separate\r
157 {\r
158 ot(" ldr r%d,[r7,#0x3c] ;@ A7\n",a);\r
159 }\r
160 else\r
161 {\r
162 EaCalcReg(2,ea,mask,0,0,1);\r
163 if(mask)\r
164 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
165 lsl=2-low; // Having a lsl #x here saves one opcode\r
166 if (lsl>=0) ot(" ldr r%d,[r7,r2,lsl #%i]\n",a,lsl);\r
167 else if (lsl<0) ot(" ldr r%d,[r7,r2,lsr #%i]\n",a,-lsl);\r
168 }\r
cc68a136 169\r
170 if ((ea&0x38)==0x18) // (An)+\r
a6785576 171 {\r
cc68a136 172 ot(" add r3,r%d,#%d ;@ Post-increment An\n",a,step);\r
a6785576 173 strr=3;\r
174 }\r
cc68a136 175\r
176 if ((ea&0x38)==0x20) // -(An)\r
177 ot(" sub r%d,r%d,#%d ;@ Pre-decrement An\n",a,a,step);\r
178\r
179 if ((ea&0x38)==0x18||(ea&0x38)==0x20)\r
a6785576 180 {\r
85a36a57 181 if (ea==0x1f||ea==0x27)\r
182 {\r
183 ot(" str r%d,[r7,#0x3c] ;@ A7\n",strr);\r
184 }\r
185 else\r
186 {\r
187 if (lsl>=0) ot(" str r%d,[r7,r2,lsl #%i]\n",strr,lsl);\r
188 else if (lsl<0) ot(" str r%d,[r7,r2,lsr #%i]\n",strr,-lsl);\r
189 }\r
cc68a136 190 }\r
191\r
192 if ((ea&0x38)==0x20) Cycles+=size<2 ? 6:10; // -(An) Extra cycles\r
193 else Cycles+=size<2 ? 4:8; // (An),(An)+ Extra cycles\r
194 return 0;\r
195 }\r
196\r
197 if (ea<0x30) // ($nn,An) (di)\r
198 {\r
cfb3dfa0 199 ot(" ldrsh r0,[r4],#2 ;@ Fetch offset\n"); pc_dirty=1;\r
b637c56a 200 EaCalcReg(2,8,mask,0,0);\r
cc68a136 201 ot(" ldr r2,[r7,r2,lsl #2]\n");\r
202 ot(" add r%d,r0,r2 ;@ Add on offset\n",a);\r
203 Cycles+=size<2 ? 8:12; // Extra cycles\r
204 return 0;\r
205 }\r
206\r
207 if (ea<0x38) // ($nn,An,Rn) (ix)\r
208 {\r
209 ot(";@ Get extension word into r3:\n");\r
cfb3dfa0 210 ot(" ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); pc_dirty=1;\r
cc68a136 211 ot(" mov r2,r3,lsr #10\n");\r
212 ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n");\r
213 ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n");\r
214 ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");\r
215 ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n");\r
216 ot(" mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n");\r
217 ot(" add r3,r2,r0,asr #24 ;@ r3=Disp+Rn\n");\r
218\r
219 EaCalcReg(2,8,mask,1,0);\r
220 ot(" ldr r2,[r7,r2,lsl #2]\n");\r
221 ot(" add r%d,r2,r3 ;@ r%d=Disp+An+Rn\n",a,a);\r
222 Cycles+=size<2 ? 10:14; // Extra cycles\r
223 return 0;\r
224 }\r
225\r
226 if (ea==0x38) // (aw)\r
227 {\r
cfb3dfa0 228 ot(" ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); pc_dirty=1;\r
cc68a136 229 Cycles+=size<2 ? 8:12; // Extra cycles\r
230 return 0;\r
231 }\r
232\r
233 if (ea==0x39) // (al)\r
234 {\r
235 ot(" ldrh r2,[r4],#2 ;@ Fetch Absolute Long address\n");\r
cfb3dfa0 236 ot(" ldrh r0,[r4],#2\n"); pc_dirty=1;\r
cc68a136 237 ot(" orr r%d,r0,r2,lsl #16\n",a);\r
238 Cycles+=size<2 ? 12:16; // Extra cycles\r
239 return 0;\r
240 }\r
241\r
242 if (ea==0x3a) // ($nn,PC) (pcdi)\r
243 {\r
244 ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n");\r
245 ot(" sub r0,r4,r0 ;@ Real PC\n");\r
cfb3dfa0 246 ot(" ldrsh r2,[r4],#2 ;@ Fetch extension\n"); pc_dirty=1;\r
cc68a136 247 ot(" mov r0,r0,lsl #8\n");\r
248 ot(" add r%d,r2,r0,asr #8 ;@ ($nn,PC)\n",a);\r
249 Cycles+=size<2 ? 8:12; // Extra cycles\r
250 return 0;\r
251 }\r
252\r
253 if (ea==0x3b) // ($nn,pc,Rn) (pcix)\r
254 {\r
255 ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n");\r
256 ot(" ldrh r3,[r4] ;@ Get extension word\n");\r
257 ot(" sub r0,r4,r0 ;@ r0=PC\n");\r
cfb3dfa0 258 ot(" add r4,r4,#2\n"); pc_dirty=1;\r
cc68a136 259 ot(" mov r0,r0,asl #8 ;@ use only 24bits of PC\n");\r
260 ot(" mov r2,r3,lsr #10\n");\r
261 ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n");\r
262 ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n");\r
263 ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");\r
264 ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n");\r
265 ot(" mov r3,r3,asl #24 ;@ r3=Get 8-bit signed Disp\n");\r
266 ot(" add r2,r2,r3,asr #24 ;@ r2=Disp+Rn\n");\r
267 ot(" add r%d,r2,r0,asr #8 ;@ r%d=Disp+PC+Rn\n",a,a);\r
268 Cycles+=size<2 ? 10:14; // Extra cycles\r
269 return 0;\r
270 }\r
271\r
272 if (ea==0x3c) // #$nnnn (i)\r
273 {\r
274 if (size<2)\r
275 {\r
cfb3dfa0 276 ot(" ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); pc_dirty=1;\r
cc68a136 277 Cycles+=4; // Extra cycles\r
278 return 0;\r
279 }\r
280\r
281 ot(" ldrh r2,[r4],#2 ;@ Fetch immediate value\n");\r
85a36a57 282 ot(" ldrh r3,[r4],#2\n"); pc_dirty=1;\r
283 ot(" orr r%d,r3,r2,lsl #16\n",a);\r
cc68a136 284 Cycles+=8; // Extra cycles\r
285 return 0;\r
286 }\r
287\r
288 return 1;\r
289}\r
290\r
291// ---------------------------------------------------------------------------\r
292// Read effective address in (ARM Register 'a') to ARM register 'v'\r
293// 'a' and 'v' can be anything but 0 is generally best (for both)\r
294// If (ea<0x10) nothing is trashed, else r0-r3 is trashed\r
295// If 'top' is given, the ARM register v shifted to the top, e.g. 0xc000 -> 0xc0000000\r
b637c56a 296// If top is 0 and sign_extend is not, then ARM register v is sign extended,\r
297// e.g. 0xc000 -> 0xffffc000 (else it may or may not be sign extended)\r
cc68a136 298\r
b637c56a 299int EaRead(int a,int v,int ea,int size,int mask,int top,int sign_extend)\r
cc68a136 300{\r
301 char text[32]="";\r
302 int shift=0;\r
3a5e6cf8 303 \r
cc68a136 304 shift=32-(8<<size);\r
305\r
306 DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address\r
307\r
308 if (ea<0x10)\r
309 {\r
3a5e6cf8 310 int lsl=0,low=0,nsarm=size&3,i;\r
b637c56a 311 if (size>=2||(size==0&&(top||!sign_extend))) {\r
a6785576 312 if(mask)\r
cc68a136 313 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
a6785576 314 lsl=2-low; // Having a lsl #2 here saves one opcode\r
315 }\r
cc68a136 316\r
85a36a57 317 if (top||!sign_extend) nsarm=3;\r
3a5e6cf8 318\r
cc68a136 319 ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v);\r
320\r
3a5e6cf8 321 if (lsl>0) ot(" ldr%s r%d,[r7,r%d,lsl #%i]\n",Narm[nsarm],v,a,lsl);\r
322 else if (lsl<0) ot(" ldr%s r%d,[r7,r%d,lsr #%i]\n",Narm[nsarm],v,a,-lsl);\r
323 else ot(" ldr%s r%d,[r7,r%d]\n",Sarm[nsarm],v,a);\r
cc68a136 324\r
3a5e6cf8 325 if (top&&shift) ot(" mov r%d,r%d,asl #%d\n",v,v,shift);\r
cc68a136 326\r
327 ot("\n"); return 0;\r
328 }\r
329\r
330 ot(";@ EaRead : Read '%s' (address in r%d) into r%d:\n",text,a,v);\r
331\r
332 if (ea==0x3c)\r
333 {\r
334 int asl=0;\r
335\r
336 if (top) asl=shift;\r
337\r
b637c56a 338 if (asl) ot(" mov r%d,r%d,asl #%d\n",v,a,asl);\r
339 else if (v!=a) ot(" mov r%d,r%d\n",v,a);\r
cc68a136 340 ot("\n"); return 0;\r
341 }\r
342\r
cfb3dfa0 343 if (ea>=0x3a && ea<=0x3b) MemHandler(2,size,a); // Fetch\r
344 else MemHandler(0,size,a); // Read\r
cc68a136 345\r
b637c56a 346 if (sign_extend)\r
347 {\r
348 int d_reg=0;\r
349 if (shift) {\r
350 ot(" mov r%d,r%d,asl #%d\n",v,d_reg,shift);\r
351 d_reg=v;\r
352 }\r
353 if (!top && shift) {\r
354 ot(" mov r%d,r%d,asr #%d\n",v,d_reg,shift);\r
355 d_reg=v;\r
356 }\r
357 if (d_reg != v)\r
358 ot(" mov r%d,r%d\n",v,d_reg);\r
359 }\r
360 else\r
361 {\r
362 if (top && shift)\r
363 ot(" mov r%d,r0,asl #%d\n",v,shift);\r
364 else if (v!=0)\r
365 ot(" mov r%d,r0\n",v);\r
cc68a136 366 }\r
cc68a136 367\r
368 ot("\n"); return 0;\r
369}\r
370\r
85a36a57 371// calculate EA and read\r
372// if (ea < 0x10) nothing is trashed\r
373// if (ea == 0x3c) r2 and r3 are trashed\r
374// else r0-r3 are trashed\r
375// size values 0, 1, 2 ~ byte, word, long\r
376// r_ea is reg to store ea in (-1 means ea is not needed), r is dst reg\r
377// if sign_extend is 0, non-32bit values will have MS bits undefined\r
378int EaCalcRead(int r_ea,int r,int ea,int size,int mask,int sign_extend)\r
379{\r
380 if (ea<0x10)\r
381 {\r
382 if (r_ea==-1)\r
383 {\r
384 r_ea=r;\r
385 if (!sign_extend) size=2;\r
386 }\r
387 }\r
388 else if (ea==0x3c) // #imm\r
389 {\r
390 r_ea=r;\r
391 }\r
392 else\r
393 {\r
394 if (r_ea==-1) r_ea=0;\r
395 }\r
396\r
397 EaCalc (r_ea,mask,ea,size,0,sign_extend);\r
398 EaRead (r_ea, r,ea,size,mask,0,sign_extend);\r
399\r
400 return 0;\r
401}\r
402\r
403int EaCalcReadNoSE(int r_ea,int r,int ea,int size,int mask)\r
404{\r
405 return EaCalcRead(r_ea,r,ea,size,mask,0);\r
406}\r
407\r
cc68a136 408// Return 1 if we can read this ea\r
409int EaCanRead(int ea,int size)\r
410{\r
411 if (size<0)\r
412 {\r
413 // LEA:\r
414 // These don't make sense?:\r
415 if (ea< 0x10) return 0; // Register\r
416 if (ea==0x3c) return 0; // Immediate\r
417 if (ea>=0x18 && ea<0x28) return 0; // Pre/Post inc/dec An\r
418 }\r
419\r
420 if (ea<=0x3c) return 1;\r
421 return 0;\r
422}\r
423\r
424// ---------------------------------------------------------------------------\r
425// Write effective address (ARM Register 'a') with ARM register 'v'\r
426// Trashes r0-r3,r12,lr; 'a' can be 0 or 2+, 'v' can be 1 or higher\r
427// If a==0 and v==1 it's faster though.\r
b637c56a 428int EaWrite(int a,int v,int ea,int size,int mask,int top,int sign_extend_ea)\r
cc68a136 429{\r
430 char text[32]="";\r
431 int shift=0;\r
432\r
433 if(a == 1) { printf("Error! EaWrite a==1 !\n"); return 1; }\r
434\r
435 if (top) shift=32-(8<<size);\r
436\r
437 DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address\r
438\r
439 if (ea<0x10)\r
440 {\r
441 int lsl=0,low=0,i;\r
b637c56a 442 if (size>=2||(size==0&&(top||!sign_extend_ea))) {\r
a6785576 443 if(mask)\r
cc68a136 444 for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
a6785576 445 lsl=2-low; // Having a lsl #x here saves one opcode\r
446 }\r
cc68a136 447\r
448 ot(";@ EaWrite: r%d into register[r%d]:\n",v,a);\r
449 if (shift) ot(" mov r%d,r%d,asr #%d\n",v,v,shift);\r
450\r
451 if (lsl>0) ot(" str%s r%d,[r7,r%d,lsl #%i]\n",Narm[size&3],v,a,lsl);\r
452 else if (lsl<0) ot(" str%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl);\r
453 else ot(" str%s r%d,[r7,r%d]\n",Narm[size&3],v,a);\r
454\r
455 ot("\n"); return 0;\r
456 }\r
457\r
458 ot(";@ EaWrite: Write r%d into '%s' (address in r%d):\n",v,text,a);\r
459\r
460 if (ea==0x3c) { ot("Error! Write EA=0x%x\n\n",ea); return 1; }\r
461\r
b637c56a 462 if (shift) ot(" mov r1,r%d,asr #%d\n",v,shift);\r
463 else if (v!=1) ot(" mov r1,r%d\n",v);\r
cc68a136 464\r
cfb3dfa0 465 MemHandler(1,size,a); // Call write handler\r
cc68a136 466\r
467 ot("\n"); return 0;\r
468}\r
469\r
470// Return 1 if we can write this ea\r
471int EaCanWrite(int ea)\r
472{\r
473 if (ea<=0x39) return 1; // 3b?\r
474 return 0;\r
475}\r
476// ---------------------------------------------------------------------------\r
477\r
478// Return 1 if EA is An reg\r
479int EaAn(int ea)\r
480{\r
481 if((ea&0x38)==8) return 1;\r
482 return 0;\r
483}\r
484\r