fix compatibility with ancient gas
[cyclone68000.git] / OpLogic.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 // trashes r0\r
16 const char *TestCond(int m68k_cc, int invert)\r
17 {\r
18   const char *cond="";\r
19   const char *icond="";\r
20 \r
21   // ARM: NZCV\r
22   switch (m68k_cc)\r
23   {\r
24     case 0x00: // T\r
25     case 0x01: // F\r
26       break;\r
27     case 0x02: // hi\r
28       ot("  tst r10,#0x60000000 ;@ hi: !C && !Z\n");\r
29       cond="eq", icond="ne";\r
30       break;\r
31     case 0x03: // ls\r
32       ot("  tst r10,#0x60000000 ;@ ls: C || Z\n");\r
33       cond="ne", icond="eq";\r
34       break;\r
35     case 0x04: // cc\r
36       ot("  tst r10,#0x20000000 ;@ cc: !C\n");\r
37       cond="eq", icond="ne";\r
38       break;\r
39     case 0x05: // cs\r
40       ot("  tst r10,#0x20000000 ;@ cs: C\n");\r
41       cond="ne", icond="eq";\r
42       break;\r
43     case 0x06: // ne\r
44       ot("  tst r10,#0x40000000 ;@ ne: !Z\n");\r
45       cond="eq", icond="ne";\r
46       break;\r
47     case 0x07: // eq\r
48       ot("  tst r10,#0x40000000 ;@ eq: Z\n");\r
49       cond="ne", icond="eq";\r
50       break;\r
51     case 0x08: // vc\r
52       ot("  tst r10,#0x10000000 ;@ vc: !V\n");\r
53       cond="eq", icond="ne";\r
54       break;\r
55     case 0x09: // vs\r
56       ot("  tst r10,#0x10000000 ;@ vs: V\n");\r
57       cond="ne", icond="eq";\r
58       break;\r
59     case 0x0a: // pl\r
60       ot("  tst r10,r10 ;@ pl: !N\n");\r
61       cond="pl", icond="mi";\r
62       break;\r
63     case 0x0b: // mi\r
64       ot("  tst r10,r10 ;@ mi: N\n");\r
65       cond="mi", icond="pl";\r
66       break;\r
67     case 0x0c: // ge\r
68       ot("  teq r10,r10,lsl #3 ;@ ge: N == V\n");\r
69       cond="pl", icond="mi";\r
70       break;\r
71     case 0x0d: // lt\r
72       ot("  teq r10,r10,lsl #3 ;@ lt: N != V\n");\r
73       cond="mi", icond="pl";\r
74       break;\r
75     case 0x0e: // gt\r
76       ot("  eor r0,r10,r10,lsl #3 ;@ gt: !Z && N == V\n");\r
77       ot("  orrs r0,r10,lsl #1\n");\r
78       cond="pl", icond="mi";\r
79       break;\r
80     case 0x0f: // le\r
81       ot("  eor r0,r10,r10,lsl #3 ;@ le: Z || N != V\n");\r
82       ot("  orrs r0,r10,lsl #1\n");\r
83       cond="mi", icond="pl";\r
84       break;\r
85     default:\r
86       printf("invalid m68k_cc: %x\n", m68k_cc);\r
87       exit(1);\r
88       break;\r
89   }\r
90   return invert?icond:cond;\r
91 }\r
92 \r
93 // --------------------- Opcodes 0x0100+ ---------------------\r
94 // Emit a Btst (Register) opcode 0000nnn1 ttaaaaaa\r
95 int OpBtstReg(int op)\r
96 {\r
97   int use=0;\r
98   int type=0,sea=0,tea=0;\r
99   int size=0;\r
100 \r
101   type=(op>>6)&3; // Btst/Bchg/Bclr/Bset\r
102   // Get source and target EA\r
103   sea=(op>>9)&7;\r
104   tea=op&0x003f;\r
105   if (tea<0x10) size=2; // For registers, 32-bits\r
106 \r
107   if ((tea&0x38)==0x08) return 1; // movep\r
108 \r
109   // See if we can do this opcode:\r
110   if (EaCanRead(tea,0)==0) return 1;\r
111   if (type>0)\r
112   {\r
113     if (EaCanWrite(tea)==0) return 1;\r
114   }\r
115 \r
116   use=OpBase(op,size);\r
117   use&=~0x0e00; // Use same handler for all registers\r
118   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
119 \r
120   OpStart(op,tea);\r
121 \r
122   if(type==1||type==3) {\r
123     Cycles=8;\r
124   } else {\r
125     Cycles=type?8:4;\r
126     if(size>=2) Cycles+=2;\r
127   }\r
128 \r
129   EaCalcRead(-1,11,sea,0,0x0e00,earwt_msb_dont_care);\r
130 \r
131   EaCalcRead((type>0)?8:-1,0,tea,size,0x003f,earwt_msb_dont_care);\r
132 \r
133   if (tea>=0x10)\r
134        ot("  and r11,r11,#7  ;@ mem - do mod 8\n");  // size always 0\r
135   else ot("  and r11,r11,#31 ;@ reg - do mod 32\n"); // size always 2\r
136   ot("\n");\r
137 \r
138   ot("  mov r1,#1\n");\r
139   ot("  tst r0,r1,lsl r11 ;@ Do arithmetic\n");\r
140   ot("  bicne r10,r10,#0x40000000\n");\r
141   ot("  orreq r10,r10,#0x40000000 ;@ Get Z flag\n");\r
142   ot("\n");\r
143 \r
144   if (type>0)\r
145   {\r
146     if (type==1) ot("  eor r1,r0,r1,lsl r11 ;@ Toggle bit\n");\r
147     if (type==2) ot("  bic r1,r0,r1,lsl r11 ;@ Clear bit\n");\r
148     if (type==3) ot("  orr r1,r0,r1,lsl r11 ;@ Set bit\n");\r
149     ot("\n");\r
150     EaWrite(8,1,tea,size,0x003f,earwt_msb_dont_care);\r
151   }\r
152   OpEnd(tea);\r
153 \r
154   return 0;\r
155 }\r
156 \r
157 // --------------------- Opcodes 0x0800+ ---------------------\r
158 // Emit a Btst/Bchg/Bclr/Bset (Immediate) opcode 00001000 ttaaaaaa nn\r
159 int OpBtstImm(int op)\r
160 {\r
161   int type=0,sea=0,tea=0;\r
162   int use=0;\r
163   int size=0;\r
164 \r
165   type=(op>>6)&3;\r
166   // Get source and target EA\r
167   sea=   0x003c;\r
168   tea=op&0x003f;\r
169   if (tea<0x10) size=2; // For registers, 32-bits\r
170 \r
171   // See if we can do this opcode:\r
172   if (EaCanRead(tea,0)==0||EaAn(tea)||tea==0x3c) return 1;\r
173   if (type>0)\r
174   {\r
175     if (EaCanWrite(tea)==0) return 1;\r
176   }\r
177 \r
178   use=OpBase(op,size);\r
179   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
180 \r
181   OpStart(op,sea,tea);\r
182 \r
183   ot("\n");\r
184   EaCalcRead(-1,0,sea,0,0,earwt_msb_dont_care);\r
185   ot("  mov r11,#1\n");\r
186   ot("  bic r10,r10,#0x40000000 ;@ Blank Z flag\n");\r
187   if (tea>=0x10)\r
188        ot("  and r0,r0,#7    ;@ mem - do mod 8\n");  // size always 0\r
189   else ot("  and r0,r0,#0x1F ;@ reg - do mod 32\n"); // size always 2\r
190   ot("  mov r11,r11,lsl r0 ;@ Make bit mask\n");\r
191   ot("\n");\r
192 \r
193   if(type==1||type==3) {\r
194     Cycles=12;\r
195   } else {\r
196     Cycles=type?12:8;\r
197     if(size>=2) Cycles+=2;\r
198   }\r
199 \r
200   EaCalcRead((type>0)?8:-1,0,tea,size,0x003f,earwt_msb_dont_care);\r
201   ot("  tst r0,r11 ;@ Do arithmetic\n");\r
202   ot("  orreq r10,r10,#0x40000000 ;@ Get Z flag\n");\r
203   ot("\n");\r
204 \r
205   if (type>0)\r
206   {\r
207     if (type==1) ot("  eor r1,r0,r11 ;@ Toggle bit\n");\r
208     if (type==2) ot("  bic r1,r0,r11 ;@ Clear bit\n");\r
209     if (type==3) ot("  orr r1,r0,r11 ;@ Set bit\n");\r
210     ot("\n");\r
211     EaWrite(8, 1,tea,size,0x003f,earwt_msb_dont_care);\r
212 #if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES\r
213     // this is a bit hacky (device handlers might modify cycles)\r
214     if (tea==0x38||tea==0x39)\r
215       ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");\r
216 #endif\r
217   }\r
218 \r
219   OpEnd(sea,tea);\r
220 \r
221   return 0;\r
222 }\r
223 \r
224 // --------------------- Opcodes 0x4000+ ---------------------\r
225 int OpNeg(int op)\r
226 {\r
227   // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA)\r
228   int type=0,size=0,ea=0,use=0;\r
229 \r
230   type=(op>>9)&3;\r
231   ea  =op&0x003f;\r
232   size=(op>>6)&3; if (size>=3) return 1;\r
233 \r
234   // See if we can do this opcode:\r
235   if (EaCanRead (ea,size)==0||EaAn(ea)) return 1;\r
236   if (EaCanWrite(ea     )==0) return 1;\r
237 \r
238   use=OpBase(op,size);\r
239   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
240 \r
241   OpStart(op,ea); Cycles=size<2?4:6;\r
242   if(ea >= 0x10)  Cycles*=2;\r
243 \r
244   EaCalc (11,0x003f,ea,size,earwt_msb_dont_care);\r
245 \r
246   if (type!=1) EaRead (11,0,ea,size,0x003f,earwt_msb_dont_care); // Don't need to read for 'clr' (or do we, for a dummy read?)\r
247   if (type==1) ot("\n");\r
248 \r
249   if (type==0)\r
250   {\r
251     ot(";@ Negx:\n");\r
252     GetXBit(1);\r
253     if(size!=2) ot("  mov r0,r0,asl #%i\n",size?16:24);\r
254     ot("  rscs r1,r0,#0 ;@ do arithmetic\n");\r
255     ot("  orr r3,r10,#0xb0000000 ;@ for old Z\n");\r
256     OpGetFlags(1,1,0);\r
257     if(size!=2) {\r
258       ot("  movs r1,r1,asr #%i\n",size?16:24);\r
259       ot("  orreq r10,r10,#0x40000000 ;@ possily missed Z\n");\r
260     }\r
261     ot("  andeq r10,r10,r3 ;@ fix Z\n");\r
262     ot("\n");\r
263   }\r
264 \r
265   if (type==1)\r
266   {\r
267     ot(";@ Clear:\n");\r
268     ot("  mov r1,#0\n");\r
269     ot("  mov r10,#0x40000000 ;@ NZCV=0100\n");\r
270     ot("\n");\r
271   }\r
272 \r
273   if (type==2)\r
274   {\r
275     ot(";@ Neg:\n");\r
276     if(size!=2) ot("  mov r0,r0,asl #%i\n",size?16:24);\r
277     ot("  rsbs r1,r0,#0\n");\r
278     OpGetFlags(1,1);\r
279     if(size!=2) ot("  mov r1,r1,asr #%i\n",size?16:24);\r
280     ot("\n");\r
281   }\r
282 \r
283   if (type==3)\r
284   {\r
285     ot(";@ Not:\n");\r
286     if(size!=2) {\r
287       ot("  mov r0,r0,asl #%i\n",size?16:24);\r
288       ot("  mvns r1,r0,asr #%i\n",size?16:24);\r
289     }\r
290     else\r
291       ot("  mvns r1,r0\n");\r
292     OpGetFlagsNZ(1);\r
293     ot("\n");\r
294   }\r
295 \r
296   if (type==1) eawrite_check_addrerr=1;\r
297   EaWrite(11, 1,ea,size,0x003f,earwt_msb_dont_care);\r
298 \r
299   OpEnd(ea);\r
300 \r
301   return 0;\r
302 }\r
303 \r
304 // --------------------- Opcodes 0x4840+ ---------------------\r
305 // Swap, 01001000 01000nnn swap Dn\r
306 int OpSwap(int op)\r
307 {\r
308   int ea=0,use=0;\r
309 \r
310   ea=op&7;\r
311   use=op&~0x0007; // Use same opcode for all An\r
312 \r
313   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
314 \r
315   OpStart(op); Cycles=4;\r
316 \r
317   EaCalc (11,0x0007,ea,2,earwt_shifted_up);\r
318   EaRead (11,     0,ea,2,0x0007,earwt_shifted_up);\r
319 \r
320   ot("  movs r1,r0,ror #16\n");\r
321   OpGetFlagsNZ(1);\r
322 \r
323   EaWrite(11,     1,8,2,0x0007,earwt_shifted_up);\r
324 \r
325   OpEnd();\r
326 \r
327   return 0;\r
328 }\r
329 \r
330 // --------------------- Opcodes 0x4a00+ ---------------------\r
331 // Emit a Tst opcode, 01001010 xxeeeeee\r
332 int OpTst(int op)\r
333 {\r
334   int sea=0;\r
335   int size=0,use=0;\r
336 \r
337   sea=op&0x003f;\r
338   size=(op>>6)&3; if (size>=3) return 1;\r
339 \r
340   // See if we can do this opcode:\r
341   if (EaCanWrite(sea)==0||EaAn(sea)) return 1;\r
342 \r
343   use=OpBase(op,size);\r
344   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
345 \r
346   OpStart(op,sea); Cycles=4;\r
347 \r
348   EaCalc (0,0x003f,sea,size,earwt_shifted_up);\r
349   EaRead (0,     0,sea,size,0x003f,earwt_shifted_up,1);\r
350 \r
351   OpGetFlagsNZ(0);\r
352   ot("\n");\r
353 \r
354   OpEnd(sea);\r
355   return 0;\r
356 }\r
357 \r
358 // --------------------- Opcodes 0x4880+ ---------------------\r
359 // Emit an Ext opcode, 01001000 1x000nnn\r
360 int OpExt(int op)\r
361 {\r
362   int ea=0;\r
363   int size=0,use=0;\r
364   int shift=0;\r
365 \r
366   ea=op&0x0007;\r
367   size=(op>>6)&1;\r
368   shift=32-(8<<size);\r
369 \r
370   use=OpBase(op,size);\r
371   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
372 \r
373   OpStart(op); Cycles=4;\r
374 \r
375   EaCalc (11,0x0007,ea,size+1,earwt_msb_dont_care);\r
376   EaRead (11,     0,ea,size+1,0x0007,earwt_msb_dont_care);\r
377 \r
378   ot("  movs r0,r0,asl #%d\n",shift);\r
379   OpGetFlagsNZ(0);\r
380   ot("  mov r1,r0,asr #%d\n",shift);\r
381   ot("\n");\r
382 \r
383   EaWrite(11,     1,ea,size+1,0x0007,earwt_msb_dont_care);\r
384 \r
385   OpEnd();\r
386   return 0;\r
387 }\r
388 \r
389 // --------------------- Opcodes 0x50c0+ ---------------------\r
390 // Emit a Set cc opcode, 0101cccc 11eeeeee\r
391 int OpSet(int op)\r
392 {\r
393   int cc=0,ea=0;\r
394   int size=0,use=0,changed_cycles=0;\r
395   const char *cond;\r
396 \r
397   cc=(op>>8)&15;\r
398   ea=op&0x003f;\r
399 \r
400   if ((ea&0x38)==0x08) return 1; // dbra, not scc\r
401   \r
402   // See if we can do this opcode:\r
403   if (EaCanWrite(ea)==0) return 1;\r
404 \r
405   use=OpBase(op,size);\r
406   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
407 \r
408   changed_cycles=ea<8 && cc>=2;\r
409   OpStart(op,ea,0,changed_cycles); Cycles=8;\r
410   if (ea<8) Cycles=4;\r
411 \r
412   switch (cc)\r
413   {\r
414     case 0x00: // T\r
415       ot("  mvn r1,#0\n");\r
416       if (ea<8) Cycles+=2;\r
417       break;\r
418     case 0x01: // F\r
419       ot("  mov r1,#0\n");\r
420       break;\r
421     default:\r
422       ot("  mov r1,#0\n");\r
423       cond=TestCond(cc);\r
424       ot("  mvn%s r1,#0\n",cond);\r
425       if (ea<8) ot("  sub%s r5,r5,#2 ;@ Extra cycles\n",cond);\r
426       break;\r
427   }\r
428 \r
429   ot("\n");\r
430 \r
431   eawrite_check_addrerr=1;\r
432   EaCalc (0,0x003f, ea,size,earwt_msb_dont_care);\r
433   EaWrite(0,     1, ea,size,0x003f,earwt_msb_dont_care);\r
434 \r
435   opend_op_changes_cycles=changed_cycles;\r
436   OpEnd(ea,0);\r
437   return 0;\r
438 }\r
439 \r
440 // Emit a Asr/Lsr/Roxr/Ror opcode\r
441 static int EmitAsr(int op,int type,int dir,int count,int size,int usereg)\r
442 {\r
443   char pct[8]=""; // count\r
444   int shift=32-(8<<size);\r
445 \r
446   if (count>=1) sprintf(pct,"#%d",count); // Fixed count\r
447 \r
448   if (usereg)\r
449   {\r
450     ot(";@ Use Dn for count:\n");\r
451     ot("  and r2,r8,#0x0e00\n");\r
452     ot("  ldr r2,[r7,r2,lsr #7]\n");\r
453     ot("  and r2,r2,#63\n");\r
454     ot("\n");\r
455     strcpy(pct,"r2");\r
456   }\r
457   else if (count<0)\r
458   {\r
459     ot("  mov r2,r8,lsr #9 ;@ Get 'n'\n");\r
460     ot("  and r2,r2,#7\n\n"); strcpy(pct,"r2");\r
461   }\r
462 \r
463   // Take 2*n cycles:\r
464   if (count<0) ot("  sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n");\r
465   else Cycles+=count<<1;\r
466 \r
467   if (type<2)\r
468   {\r
469     // Asr/Lsr\r
470     if (dir==0 && size<2)\r
471     {\r
472       ot(";@ For shift right, use loworder bits for the operation:\n");\r
473       ot("  mov r0,r0,%s #%d\n",type?"lsr":"asr",32-(8<<size));\r
474       ot("\n");\r
475     }\r
476 \r
477     if (type==0 && dir) ot("  adds r3,r0,#0 ;@ save old value for V flag calculation, also clear V\n");\r
478 \r
479     ot(";@ Shift register:\n");\r
480     if (type==0) ot("  movs r0,r0,%s %s\n",dir?"asl":"asr",pct);\r
481     if (type==1) ot("  movs r0,r0,%s %s\n",dir?"lsl":"lsr",pct);\r
482 \r
483     OpGetFlags(0,0);\r
484     if (usereg) { // store X only if count is not 0\r
485       ot("  cmp %s,#0 ;@ shifting by 0?\n",pct);\r
486       ot("  biceq r10,r10,#0x20000000 ;@ if so, clear carry\n");\r
487       ot("  strne r10,[r7,#0x4c] ;@ else Save X bit\n");\r
488     } else {\r
489       // count will never be 0 if we use immediate\r
490       ot("  str r10,[r7,#0x4c] ;@ Save X bit\n");\r
491     }\r
492     ot("\n");\r
493 \r
494     if (dir==0 && size<2)\r
495     {\r
496       ot(";@ restore after right shift:\n");\r
497       ot("  movs r0,r0,lsl #%d\n",32-(8<<size));\r
498       if (type)\r
499         ot("  orrmi r10,r10,#0x80000000 ;@ Potentially missed N flag\n");\r
500       ot("\n");\r
501     }\r
502 \r
503     if (type==0 && dir) {\r
504       ot(";@ calculate V flag (set if sign bit changes at anytime):\n");\r
505       ot("  mov r1,#0x80000000\n");\r
506       ot("  ands r3,r3,r1,asr %s\n", pct);\r
507       ot("  cmpne r3,r1,asr %s\n", pct);\r
508       ot("  eoreq r1,r0,r3\n"); // above check doesn't catch (-1)<<(32+), so we need this\r
509       ot("  tsteq r1,#0x80000000\n");\r
510       ot("  orrne r10,r10,#0x10000000\n");\r
511       ot("\n");\r
512     }\r
513   }\r
514 \r
515   // --------------------------------------\r
516   if (type==2)\r
517   {\r
518     int wide=8<<size;\r
519 \r
520     // Roxr\r
521     if(count == 1)\r
522     {\r
523       if(dir==0) {\r
524         if(size!=2) {\r
525           ot("  orr r0,r0,r0,lsr #%i\n", size?16:24);\r
526           ot("  bic r0,r0,#0x%x\n", 1<<(32-wide));\r
527         }\r
528         GetXBit(0);\r
529         ot("  movs r0,r0,rrx\n");\r
530         OpGetFlags(0,1);\r
531       } else {\r
532         ot("  ldr r3,[r7,#0x4c]\n");\r
533         ot("  movs r0,r0,lsl #1\n");\r
534         OpGetFlags(0,1);\r
535         ot("  tst r3,#0x20000000\n");\r
536         ot("  orrne r0,r0,#0x%x\n", 1<<(32-wide));\r
537         ot("  bicne r10,r10,#0x40000000 ;@ clear Z in case it got there\n");\r
538       }\r
539       ot("  bic r10,r10,#0x10000000 ;@ make suve V is clear\n");\r
540       return 0;\r
541     }\r
542 \r
543     if (usereg)\r
544     {\r
545       if (size==2)\r
546       {\r
547         ot("  subs r2,r2,#33\n");\r
548         ot("  addmis r2,r2,#33 ;@ Now r2=0-%d\n",wide);\r
549       }\r
550       else\r
551       {\r
552         ot(";@ Reduce r2 until <0:\n");\r
553         ot("Reduce_%.4x%s\n",op,ms?"":":");\r
554         ot("  subs r2,r2,#%d\n",wide+1);\r
555         ot("  bpl Reduce_%.4x\n",op);\r
556         ot("  adds r2,r2,#%d ;@ Now r2=0-%d\n",wide+1,wide);\r
557       }\r
558       ot("  beq norotx_%.4x\n",op);\r
559       ot("\n");\r
560     }\r
561 \r
562     if (usereg||count < 0)\r
563     {\r
564       if (dir) ot("  rsb r2,r2,#%d ;@ Reverse direction\n",wide+1);\r
565     }\r
566     else\r
567     {\r
568       if (dir) ot("  mov r2,#%d ;@ Reversed\n",wide+1-count);\r
569       else     ot("  mov r2,#%d\n",count);\r
570     }\r
571 \r
572     if (shift) ot("  mov r0,r0,lsr #%d ;@ Shift down\n",shift);\r
573 \r
574     ot("\n");\r
575     ot(";@ First get X bit (middle):\n");\r
576     ot("  ldr r3,[r7,#0x4c]\n");\r
577     ot("  rsb r1,r2,#%d\n",wide);\r
578     ot("  and r3,r3,#0x20000000\n");\r
579     ot("  mov r3,r3,lsr #29\n");\r
580     ot("  mov r3,r3,lsl r1\n");\r
581 \r
582     ot(";@ Rotate bits:\n");\r
583     ot("  orr r3,r3,r0,lsr r2 ;@ Orr right part\n");\r
584     ot("  rsbs r2,r2,#%d ;@ should also clear ARM V\n",wide+1);\r
585     ot("  orrs r0,r3,r0,lsl r2 ;@ Orr left part, set flags\n");\r
586     ot("\n");\r
587 \r
588     if (shift) ot("  movs r0,r0,lsl #%d ;@ Shift up and get correct NC flags\n",shift);\r
589     OpGetFlags(0,!usereg);\r
590     if (usereg) { // store X only if count is not 0\r
591       ot("  str r10,[r7,#0x4c] ;@ if not 0, Save X bit\n");\r
592       ot("  b nozerox%.4x\n",op);\r
593       ot("norotx_%.4x%s\n",op,ms?"":":");\r
594       ot("  ldr r2,[r7,#0x4c]\n");\r
595       ot("  adds r0,r0,#0 ;@ Define flags\n");\r
596       OpGetFlagsNZ(0);\r
597       ot("  and r2,r2,#0x20000000\n");\r
598       ot("  orr r10,r10,r2 ;@ C = old_X\n");\r
599       ot("nozerox%.4x%s\n",op,ms?"":":");\r
600     }\r
601 \r
602     ot("\n");\r
603   }\r
604 \r
605   // --------------------------------------\r
606   if (type==3)\r
607   {\r
608     // Ror\r
609     if (size<2)\r
610     {\r
611       ot(";@ Mirror value in whole 32 bits:\n");\r
612       if (size<=0) ot("  orr r0,r0,r0,lsr #8\n");\r
613       if (size<=1) ot("  orr r0,r0,r0,lsr #16\n");\r
614       ot("\n");\r
615     }\r
616 \r
617     ot(";@ Rotate register:\n");\r
618     if (!dir) ot("  adds r0,r0,#0 ;@ first clear V and C\n"); // ARM does not clear C if rot count is 0\r
619     if (count<0)\r
620     {\r
621       if (dir) ot("  rsb %s,%s,#32\n",pct,pct);\r
622       ot("  movs r0,r0,ror %s\n",pct);\r
623     }\r
624     else\r
625     {\r
626       int ror=count;\r
627       if (dir) ror=32-ror;\r
628       if (ror&31) ot("  movs r0,r0,ror #%d\n",ror);\r
629     }\r
630 \r
631     OpGetFlags(0,0);\r
632     if (dir)\r
633     {\r
634       ot("  bic r10,r10,#0x30000000 ;@ clear CV\n");\r
635       ot(";@ Get carry bit from bit 0:\n");\r
636       if (usereg)\r
637       {\r
638         ot("  cmp %s,#32 ;@ rotating by 0?\n",pct);\r
639         ot("  tstne r0,#1 ;@ no, check bit 0\n");\r
640       }\r
641       else\r
642         ot("  tst r0,#1\n");\r
643       ot("  orrne r10,r10,#0x20000000\n");\r
644     }\r
645     ot("\n");\r
646 \r
647   }\r
648   // --------------------------------------\r
649   \r
650   return 0;\r
651 }\r
652 \r
653 // Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn\r
654 // (ccc=count, d=direction(r,l) xx=size extension, u=use reg for count, tt=type, nnn=register Dn)\r
655 int OpAsr(int op)\r
656 {\r
657   int ea=0,use=0;\r
658   int count=0,dir=0;\r
659   int size=0,usereg=0,type=0;\r
660 \r
661   count =(op>>9)&7;\r
662   dir   =(op>>8)&1;\r
663   size  =(op>>6)&3;\r
664   if (size>=3) return 1; // use OpAsrEa()\r
665   usereg=(op>>5)&1;\r
666   type  =(op>>3)&3;\r
667 \r
668   if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8\r
669 \r
670   // Use the same opcode for target registers:\r
671   use=op&~0x0007;\r
672 \r
673   // As long as count is not 8, use the same opcode for all shift counts:\r
674   if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; }\r
675   if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn\r
676 \r
677   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
678 \r
679   OpStart(op,ea,0,count<0); Cycles=size<2?6:8;\r
680 \r
681   EaCalc(11,0x0007, ea,size,earwt_shifted_up);\r
682   EaRead(11,     0, ea,size,0x0007,earwt_shifted_up);\r
683 \r
684   EmitAsr(op,type,dir,count, size,usereg);\r
685 \r
686   EaWrite(11,    0, ea,size,0x0007,earwt_shifted_up);\r
687 \r
688   opend_op_changes_cycles = (count<0);\r
689   OpEnd(ea,0);\r
690 \r
691   return 0;\r
692 }\r
693 \r
694 // Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee \r
695 int OpAsrEa(int op)\r
696 {\r
697   int use=0,type=0,dir=0,ea=0,size=1;\r
698 \r
699   type=(op>>9)&3;\r
700   dir =(op>>8)&1;\r
701   ea  = op&0x3f;\r
702 \r
703   if (ea<0x10) return 1;\r
704   // See if we can do this opcode:\r
705   if (EaCanRead(ea,0)==0) return 1;\r
706   if (EaCanWrite(ea)==0) return 1;\r
707 \r
708   use=OpBase(op,size);\r
709   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
710 \r
711   OpStart(op,ea); Cycles=6; // EmitAsr() will add 2\r
712 \r
713   EaCalc (11,0x003f,ea,size,earwt_shifted_up);\r
714   EaRead (11,     0,ea,size,0x003f,earwt_shifted_up);\r
715 \r
716   EmitAsr(op,type,dir,1,size,0);\r
717 \r
718   EaWrite(11,     0,ea,size,0x003f,earwt_shifted_up);\r
719 \r
720   OpEnd(ea);\r
721   return 0;\r
722 }\r
723 \r
724 int OpTas(int op, int gen_special)\r
725 {\r
726   int ea=0;\r
727   int use=0;\r
728 \r
729   ea=op&0x003f;\r
730 \r
731   // See if we can do this opcode:\r
732   if (EaCanWrite(ea)==0 || EaAn(ea)) return 1;\r
733 \r
734   use=OpBase(op,0);\r
735   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
736 \r
737   if (!gen_special) OpStart(op,ea);\r
738   else\r
739     ot("Op%.4x_%s\n", op, ms?"":":");\r
740 \r
741   Cycles=4;\r
742   if(ea>=8) Cycles+=10;\r
743 \r
744   EaCalc (11,0x003f,ea,0,earwt_shifted_up);\r
745   EaRead (11,     1,ea,0,0x003f,earwt_shifted_up,1);\r
746 \r
747   OpGetFlagsNZ(1);\r
748   ot("\n");\r
749 \r
750 #if CYCLONE_FOR_GENESIS\r
751   // the original Sega hardware ignores write-back phase (to memory only)\r
752   if (ea < 0x10 || gen_special) {\r
753 #endif\r
754     ot("  orr r1,r1,#0x80000000 ;@ set bit7\n");\r
755 \r
756     EaWrite(11,   1,ea,0,0x003f,earwt_shifted_up);\r
757 #if CYCLONE_FOR_GENESIS\r
758   }\r
759 #endif\r
760 \r
761   OpEnd(ea);\r
762 \r
763 #if (CYCLONE_FOR_GENESIS == 2)\r
764   if (!gen_special && ea >= 0x10) {\r
765     OpTas(op, 1);\r
766   }\r
767 #endif\r
768 \r
769   return 0;\r
770 }\r
771 \r