8b103c93bd0a1e830bcbb0a483646e131015c25c
[picodrive.git] / cpu / Cyclone / Ea.cpp
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
8 int 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
21 int 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
34 int 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
47 int 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
60 int 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
73 int Ea_add_ns(int *tab, int ea)\r
74 {\r
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
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
93 static 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
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
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
124 // If ea>=0x10, trashes r0,r2 and r3, else nothing\r
125 // size values 0, 1, 2 ~ byte, word, long\r
126 // mask shows usable bits in r8\r
127 int EaCalc(int a,int mask,int ea,int size,int top,int sign_extend)\r
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
138     if (size>=2||(size==0&&(top||!sign_extend))) noshift=1; // Saves one opcode\r
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
151     int low=0,lsl,i;\r
152 \r
153     if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1\r
154 \r
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
168 \r
169     if ((ea&0x38)==0x18) // (An)+\r
170     {\r
171       ot("  add r3,r%d,#%d ;@ Post-increment An\n",a,step);\r
172       strr=3;\r
173     }\r
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
179     {\r
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
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
198     ot("  ldrsh r0,[r4],#2 ;@ Fetch offset\n"); pc_dirty=1;\r
199     EaCalcReg(2,8,mask,0,0);\r
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
209     ot("  ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); pc_dirty=1;\r
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
227     ot("  ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); pc_dirty=1;\r
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
235     ot("  ldrh r0,[r4],#2\n"); pc_dirty=1;\r
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
245     ot("  ldrsh r2,[r4],#2 ;@ Fetch extension\n"); pc_dirty=1;\r
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
257     ot("  add r4,r4,#2\n"); pc_dirty=1;\r
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
275       ot("  ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); pc_dirty=1;\r
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
281     ot("  ldrh r3,[r4],#2\n"); pc_dirty=1;\r
282     ot("  orr r%d,r3,r2,lsl #16\n",a);\r
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
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
297 \r
298 int EaRead(int a,int v,int ea,int size,int mask,int top,int sign_extend)\r
299 {\r
300   char text[32]="";\r
301   int shift=0;\r
302  \r
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
309     int lsl=0,low=0,nsarm=size&3,i;\r
310     if (size>=2||(size==0&&(top||!sign_extend))) {\r
311       if(mask)\r
312         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
313       lsl=2-low; // Having a lsl #2 here saves one opcode\r
314     }\r
315 \r
316     if (top||!sign_extend) nsarm=3;\r
317 \r
318     ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v);\r
319 \r
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
323 \r
324     if (top&&shift) ot("  mov r%d,r%d,asl #%d\n",v,v,shift);\r
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
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
339     ot("\n"); return 0;\r
340   }\r
341 \r
342   if (ea>=0x3a && ea<=0x3b) MemHandler(2,size,a); // Fetch\r
343   else                      MemHandler(0,size,a); // Read\r
344 \r
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
365   }\r
366 \r
367   ot("\n"); return 0;\r
368 }\r
369 \r
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
377 int 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
402 int 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
407 // Return 1 if we can read this ea\r
408 int 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
427 int EaWrite(int a,int v,int ea,int size,int mask,int top,int sign_extend_ea)\r
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
441     if (size>=2||(size==0&&(top||!sign_extend_ea))) {\r
442       if(mask)\r
443         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
444       lsl=2-low; // Having a lsl #x here saves one opcode\r
445     }\r
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
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
463 \r
464   MemHandler(1,size,a); // Call write handler\r
465 \r
466   ot("\n"); return 0;\r
467 }\r
468 \r
469 // Return 1 if we can write this ea\r
470 int 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
478 int EaAn(int ea)\r
479 {\r
480   if((ea&0x38)==8) return 1;\r
481   return 0;\r
482 }\r
483 \r