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