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