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