35f0048a4d2ddbc8769891b41ec7f8d8375e3905
[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)\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
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
125 // If ea>=0x10, trashes r0,r2 and r3, else nothing\r
126 // size values 0, 1, 2 ~ byte, word, long\r
127 // mask shows usable bits in r8\r
128 int EaCalc(int a,int mask,int ea,int size,int top,int sign_extend)\r
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
139     if (size>=2||(size==0&&(top||!sign_extend))) noshift=1; // Saves one opcode\r
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
152     int low=0,lsl,i;\r
153 \r
154     if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1\r
155 \r
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
169 \r
170     if ((ea&0x38)==0x18) // (An)+\r
171     {\r
172       ot("  add r3,r%d,#%d ;@ Post-increment An\n",a,step);\r
173       strr=3;\r
174     }\r
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
180     {\r
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
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
199     ot("  ldrsh r0,[r4],#2 ;@ Fetch offset\n"); pc_dirty=1;\r
200     EaCalcReg(2,8,mask,0,0);\r
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
210     ot("  ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); pc_dirty=1;\r
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
228     ot("  ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); pc_dirty=1;\r
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
236     ot("  ldrh r0,[r4],#2\n"); pc_dirty=1;\r
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
246     ot("  ldrsh r2,[r4],#2 ;@ Fetch extension\n"); pc_dirty=1;\r
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
258     ot("  add r4,r4,#2\n"); pc_dirty=1;\r
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
276       ot("  ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); pc_dirty=1;\r
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
282     ot("  ldrh r3,[r4],#2\n"); pc_dirty=1;\r
283     ot("  orr r%d,r3,r2,lsl #16\n",a);\r
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
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
298 \r
299 int EaRead(int a,int v,int ea,int size,int mask,int top,int sign_extend)\r
300 {\r
301   char text[32]="";\r
302   int shift=0;\r
303  \r
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
310     int lsl=0,low=0,nsarm=size&3,i;\r
311     if (size>=2||(size==0&&(top||!sign_extend))) {\r
312       if(mask)\r
313         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
314       lsl=2-low; // Having a lsl #2 here saves one opcode\r
315     }\r
316 \r
317     if (top||!sign_extend) nsarm=3;\r
318 \r
319     ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v);\r
320 \r
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
324 \r
325     if (top&&shift) ot("  mov r%d,r%d,asl #%d\n",v,v,shift);\r
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
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
340     ot("\n"); return 0;\r
341   }\r
342 \r
343   if (ea>=0x3a && ea<=0x3b) MemHandler(2,size,a); // Fetch\r
344   else                      MemHandler(0,size,a); // Read\r
345 \r
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
366   }\r
367 \r
368   ot("\n"); return 0;\r
369 }\r
370 \r
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
378 int 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
403 int 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
408 // Return 1 if we can read this ea\r
409 int 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
428 int EaWrite(int a,int v,int ea,int size,int mask,int top,int sign_extend_ea)\r
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
442     if (size>=2||(size==0&&(top||!sign_extend_ea))) {\r
443       if(mask)\r
444         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is\r
445       lsl=2-low; // Having a lsl #x here saves one opcode\r
446     }\r
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
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
464 \r
465   MemHandler(1,size,a); // Call write handler\r
466 \r
467   ot("\n"); return 0;\r
468 }\r
469 \r
470 // Return 1 if we can write this ea\r
471 int 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
479 int EaAn(int ea)\r
480 {\r
481   if((ea&0x38)==8) return 1;\r
482   return 0;\r
483 }\r
484 \r