avoid using msr
[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   EaCalcReadNoSE(-1,11,sea,0,0x0e00);\r
130 \r
131   EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f);\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,0,0);\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   EaCalcReadNoSE(-1,0,sea,0,0);\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   EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f);\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,0,0);\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,0,0);\r
245 \r
246   if (type!=1) EaRead (11,0,ea,size,0x003f,0,0); // 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("  mvn r1,r0,asr #%i\n",size?16:24);\r
289     }\r
290     else\r
291       ot("  mvn r1,r0\n");\r
292     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
293     OpGetFlags(0,0);\r
294     ot("\n");\r
295   }\r
296 \r
297   if (type==1) eawrite_check_addrerr=1;\r
298   EaWrite(11,     1,ea,size,0x003f,0,0);\r
299 \r
300   OpEnd(ea);\r
301 \r
302   return 0;\r
303 }\r
304 \r
305 // --------------------- Opcodes 0x4840+ ---------------------\r
306 // Swap, 01001000 01000nnn swap Dn\r
307 int OpSwap(int op)\r
308 {\r
309   int ea=0,use=0;\r
310 \r
311   ea=op&7;\r
312   use=op&~0x0007; // Use same opcode for all An\r
313 \r
314   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
315 \r
316   OpStart(op); Cycles=4;\r
317 \r
318   EaCalc (11,0x0007,ea,2,1);\r
319   EaRead (11,     0,ea,2,0x0007,1);\r
320 \r
321   ot("  mov r1,r0,ror #16\n");\r
322   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
323   OpGetFlags(0,0);\r
324 \r
325   EaWrite(11,     1,8,2,0x0007,1);\r
326 \r
327   OpEnd();\r
328 \r
329   return 0;\r
330 }\r
331 \r
332 // --------------------- Opcodes 0x4a00+ ---------------------\r
333 // Emit a Tst opcode, 01001010 xxeeeeee\r
334 int OpTst(int op)\r
335 {\r
336   int sea=0;\r
337   int size=0,use=0;\r
338 \r
339   sea=op&0x003f;\r
340   size=(op>>6)&3; if (size>=3) return 1;\r
341 \r
342   // See if we can do this opcode:\r
343   if (EaCanWrite(sea)==0||EaAn(sea)) return 1;\r
344 \r
345   use=OpBase(op,size);\r
346   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
347 \r
348   OpStart(op,sea); Cycles=4;\r
349 \r
350   EaCalc ( 0,0x003f,sea,size,1);\r
351   EaRead ( 0,     0,sea,size,0x003f,1);\r
352 \r
353   ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");\r
354   ot("  mrs r10,cpsr ;@ r10=flags\n");\r
355   ot("\n");\r
356 \r
357   OpEnd(sea);\r
358   return 0;\r
359 }\r
360 \r
361 // --------------------- Opcodes 0x4880+ ---------------------\r
362 // Emit an Ext opcode, 01001000 1x000nnn\r
363 int OpExt(int op)\r
364 {\r
365   int ea=0;\r
366   int size=0,use=0;\r
367   int shift=0;\r
368 \r
369   ea=op&0x0007;\r
370   size=(op>>6)&1;\r
371   shift=32-(8<<size);\r
372 \r
373   use=OpBase(op,size);\r
374   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
375 \r
376   OpStart(op); Cycles=4;\r
377 \r
378   EaCalc (11,0x0007,ea,size+1,0,0);\r
379   EaRead (11,     0,ea,size+1,0x0007,0,0);\r
380 \r
381   ot("  mov r0,r0,asl #%d\n",shift);\r
382   ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");\r
383   ot("  mrs r10,cpsr ;@ r10=flags\n");\r
384   ot("  mov r1,r0,asr #%d\n",shift);\r
385   ot("\n");\r
386 \r
387   EaWrite(11,     1,ea,size+1,0x0007,0,0);\r
388 \r
389   OpEnd();\r
390   return 0;\r
391 }\r
392 \r
393 // --------------------- Opcodes 0x50c0+ ---------------------\r
394 // Emit a Set cc opcode, 0101cccc 11eeeeee\r
395 int OpSet(int op)\r
396 {\r
397   int cc=0,ea=0;\r
398   int size=0,use=0,changed_cycles=0;\r
399   const char *cond;\r
400 \r
401   cc=(op>>8)&15;\r
402   ea=op&0x003f;\r
403 \r
404   if ((ea&0x38)==0x08) return 1; // dbra, not scc\r
405   \r
406   // See if we can do this opcode:\r
407   if (EaCanWrite(ea)==0) return 1;\r
408 \r
409   use=OpBase(op,size);\r
410   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
411 \r
412   changed_cycles=ea<8 && cc>=2;\r
413   OpStart(op,ea,0,changed_cycles); Cycles=8;\r
414   if (ea<8) Cycles=4;\r
415 \r
416   switch (cc)\r
417   {\r
418     case 0x00: // T\r
419       ot("  mvn r1,#0\n");\r
420       if (ea<8) Cycles+=2;\r
421       break;\r
422     case 0x01: // F\r
423       ot("  mov r1,#0\n");\r
424       break;\r
425     default:\r
426       ot("  mov r1,#0\n");\r
427       cond=TestCond(cc);\r
428       ot("  mvn%s r1,#0\n",cond);\r
429       if (ea<8) ot("  sub%s r5,r5,#2 ;@ Extra cycles\n",cond);\r
430       break;\r
431   }\r
432 \r
433   ot("\n");\r
434 \r
435   eawrite_check_addrerr=1;\r
436   EaCalc (0,0x003f, ea,size,0,0);\r
437   EaWrite(0,     1, ea,size,0x003f,0,0);\r
438 \r
439   opend_op_changes_cycles=changed_cycles;\r
440   OpEnd(ea,0);\r
441   return 0;\r
442 }\r
443 \r
444 // Emit a Asr/Lsr/Roxr/Ror opcode\r
445 static int EmitAsr(int op,int type,int dir,int count,int size,int usereg)\r
446 {\r
447   char pct[8]=""; // count\r
448   int shift=32-(8<<size);\r
449 \r
450   if (count>=1) sprintf(pct,"#%d",count); // Fixed count\r
451 \r
452   if (usereg)\r
453   {\r
454     ot(";@ Use Dn for count:\n");\r
455     ot("  and r2,r8,#0x0e00\n");\r
456     ot("  ldr r2,[r7,r2,lsr #7]\n");\r
457     ot("  and r2,r2,#63\n");\r
458     ot("\n");\r
459     strcpy(pct,"r2");\r
460   }\r
461   else if (count<0)\r
462   {\r
463     ot("  mov r2,r8,lsr #9 ;@ Get 'n'\n");\r
464     ot("  and r2,r2,#7\n\n"); strcpy(pct,"r2");\r
465   }\r
466 \r
467   // Take 2*n cycles:\r
468   if (count<0) ot("  sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n");\r
469   else Cycles+=count<<1;\r
470 \r
471   if (type<2)\r
472   {\r
473     // Asr/Lsr\r
474     if (dir==0 && size<2)\r
475     {\r
476       ot(";@ For shift right, use loworder bits for the operation:\n");\r
477       ot("  mov r0,r0,%s #%d\n",type?"lsr":"asr",32-(8<<size));\r
478       ot("\n");\r
479     }\r
480 \r
481     if (type==0 && dir) ot("  adds r3,r0,#0 ;@ save old value for V flag calculation, also clear V\n");\r
482 \r
483     ot(";@ Shift register:\n");\r
484     if (type==0) ot("  movs r0,r0,%s %s\n",dir?"asl":"asr",pct);\r
485     if (type==1) ot("  movs r0,r0,%s %s\n",dir?"lsl":"lsr",pct);\r
486 \r
487     OpGetFlags(0,0);\r
488     if (usereg) { // store X only if count is not 0\r
489       ot("  cmp %s,#0 ;@ shifting by 0?\n",pct);\r
490       ot("  biceq r10,r10,#0x20000000 ;@ if so, clear carry\n");\r
491       ot("  strne r10,[r7,#0x4c] ;@ else Save X bit\n");\r
492     } else {\r
493       // count will never be 0 if we use immediate\r
494       ot("  str r10,[r7,#0x4c] ;@ Save X bit\n");\r
495     }\r
496     ot("\n");\r
497 \r
498     if (dir==0 && size<2)\r
499     {\r
500       ot(";@ restore after right shift:\n");\r
501       ot("  movs r0,r0,lsl #%d\n",32-(8<<size));\r
502       if (type)\r
503         ot("  orrmi r10,r10,#0x80000000 ;@ Potentially missed N flag\n");\r
504       ot("\n");\r
505     }\r
506 \r
507     if (type==0 && dir) {\r
508       ot(";@ calculate V flag (set if sign bit changes at anytime):\n");\r
509       ot("  mov r1,#0x80000000\n");\r
510       ot("  ands r3,r3,r1,asr %s\n", pct);\r
511       ot("  cmpne r3,r1,asr %s\n", pct);\r
512       ot("  eoreq r1,r0,r3\n"); // above check doesn't catch (-1)<<(32+), so we need this\r
513       ot("  tsteq r1,#0x80000000\n");\r
514       ot("  orrne r10,r10,#0x10000000\n");\r
515       ot("\n");\r
516     }\r
517   }\r
518 \r
519   // --------------------------------------\r
520   if (type==2)\r
521   {\r
522     int wide=8<<size;\r
523 \r
524     // Roxr\r
525     if(count == 1)\r
526     {\r
527       if(dir==0) {\r
528         if(size!=2) {\r
529           ot("  orr r0,r0,r0,lsr #%i\n", size?16:24);\r
530           ot("  bic r0,r0,#0x%x\n", 1<<(32-wide));\r
531         }\r
532         GetXBit(0);\r
533         ot("  movs r0,r0,rrx\n");\r
534         OpGetFlags(0,1);\r
535       } else {\r
536         ot("  ldr r3,[r7,#0x4c]\n");\r
537         ot("  movs r0,r0,lsl #1\n");\r
538         OpGetFlags(0,1);\r
539         ot("  tst r3,#0x20000000\n");\r
540         ot("  orrne r0,r0,#0x%x\n", 1<<(32-wide));\r
541         ot("  bicne r10,r10,#0x40000000 ;@ clear Z in case it got there\n");\r
542       }\r
543       ot("  bic r10,r10,#0x10000000 ;@ make suve V is clear\n");\r
544       return 0;\r
545     }\r
546 \r
547     if (usereg)\r
548     {\r
549       if (size==2)\r
550       {\r
551         ot("  subs r2,r2,#33\n");\r
552         ot("  addmis r2,r2,#33 ;@ Now r2=0-%d\n",wide);\r
553       }\r
554       else\r
555       {\r
556         ot(";@ Reduce r2 until <0:\n");\r
557         ot("Reduce_%.4x%s\n",op,ms?"":":");\r
558         ot("  subs r2,r2,#%d\n",wide+1);\r
559         ot("  bpl Reduce_%.4x\n",op);\r
560         ot("  adds r2,r2,#%d ;@ Now r2=0-%d\n",wide+1,wide);\r
561       }\r
562       ot("  beq norotx_%.4x\n",op);\r
563       ot("\n");\r
564     }\r
565 \r
566     if (usereg||count < 0)\r
567     {\r
568       if (dir) ot("  rsb r2,r2,#%d ;@ Reverse direction\n",wide+1);\r
569     }\r
570     else\r
571     {\r
572       if (dir) ot("  mov r2,#%d ;@ Reversed\n",wide+1-count);\r
573       else     ot("  mov r2,#%d\n",count);\r
574     }\r
575 \r
576     if (shift) ot("  mov r0,r0,lsr #%d ;@ Shift down\n",shift);\r
577 \r
578     ot("\n");\r
579     ot(";@ First get X bit (middle):\n");\r
580     ot("  ldr r3,[r7,#0x4c]\n");\r
581     ot("  rsb r1,r2,#%d\n",wide);\r
582     ot("  and r3,r3,#0x20000000\n");\r
583     ot("  mov r3,r3,lsr #29\n");\r
584     ot("  mov r3,r3,lsl r1\n");\r
585 \r
586     ot(";@ Rotate bits:\n");\r
587     ot("  orr r3,r3,r0,lsr r2 ;@ Orr right part\n");\r
588     ot("  rsbs r2,r2,#%d ;@ should also clear ARM V\n",wide+1);\r
589     ot("  orrs r0,r3,r0,lsl r2 ;@ Orr left part, set flags\n");\r
590     ot("\n");\r
591 \r
592     if (shift) ot("  movs r0,r0,lsl #%d ;@ Shift up and get correct NC flags\n",shift);\r
593     OpGetFlags(0,!usereg);\r
594     if (usereg) { // store X only if count is not 0\r
595       ot("  str r10,[r7,#0x4c] ;@ if not 0, Save X bit\n");\r
596       ot("  b nozerox%.4x\n",op);\r
597       ot("norotx_%.4x%s\n",op,ms?"":":");\r
598       ot("  ldr r2,[r7,#0x4c]\n");\r
599       ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");\r
600       OpGetFlags(0,0);\r
601       ot("  and r2,r2,#0x20000000\n");\r
602       ot("  orr r10,r10,r2 ;@ C = old_X\n");\r
603       ot("nozerox%.4x%s\n",op,ms?"":":");\r
604     }\r
605 \r
606     ot("\n");\r
607   }\r
608 \r
609   // --------------------------------------\r
610   if (type==3)\r
611   {\r
612     // Ror\r
613     if (size<2)\r
614     {\r
615       ot(";@ Mirror value in whole 32 bits:\n");\r
616       if (size<=0) ot("  orr r0,r0,r0,lsr #8\n");\r
617       if (size<=1) ot("  orr r0,r0,r0,lsr #16\n");\r
618       ot("\n");\r
619     }\r
620 \r
621     ot(";@ Rotate register:\n");\r
622     if (!dir) ot("  adds r0,r0,#0 ;@ first clear V and C\n"); // ARM does not clear C if rot count is 0\r
623     if (count<0)\r
624     {\r
625       if (dir) ot("  rsb %s,%s,#32\n",pct,pct);\r
626       ot("  movs r0,r0,ror %s\n",pct);\r
627     }\r
628     else\r
629     {\r
630       int ror=count;\r
631       if (dir) ror=32-ror;\r
632       if (ror&31) ot("  movs r0,r0,ror #%d\n",ror);\r
633     }\r
634 \r
635     OpGetFlags(0,0);\r
636     if (dir)\r
637     {\r
638       ot("  bic r10,r10,#0x30000000 ;@ clear CV\n");\r
639       ot(";@ Get carry bit from bit 0:\n");\r
640       if (usereg)\r
641       {\r
642         ot("  cmp %s,#32 ;@ rotating by 0?\n",pct);\r
643         ot("  tstne r0,#1 ;@ no, check bit 0\n");\r
644       }\r
645       else\r
646         ot("  tst r0,#1\n");\r
647       ot("  orrne r10,r10,#0x20000000\n");\r
648     }\r
649     ot("\n");\r
650 \r
651   }\r
652   // --------------------------------------\r
653   \r
654   return 0;\r
655 }\r
656 \r
657 // Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn\r
658 // (ccc=count, d=direction(r,l) xx=size extension, u=use reg for count, tt=type, nnn=register Dn)\r
659 int OpAsr(int op)\r
660 {\r
661   int ea=0,use=0;\r
662   int count=0,dir=0;\r
663   int size=0,usereg=0,type=0;\r
664 \r
665   count =(op>>9)&7;\r
666   dir   =(op>>8)&1;\r
667   size  =(op>>6)&3;\r
668   if (size>=3) return 1; // use OpAsrEa()\r
669   usereg=(op>>5)&1;\r
670   type  =(op>>3)&3;\r
671 \r
672   if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8\r
673 \r
674   // Use the same opcode for target registers:\r
675   use=op&~0x0007;\r
676 \r
677   // As long as count is not 8, use the same opcode for all shift counts:\r
678   if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; }\r
679   if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn\r
680 \r
681   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
682 \r
683   OpStart(op,ea,0,count<0); Cycles=size<2?6:8;\r
684 \r
685   EaCalc(11,0x0007, ea,size,1);\r
686   EaRead(11,     0, ea,size,0x0007,1);\r
687 \r
688   EmitAsr(op,type,dir,count, size,usereg);\r
689 \r
690   EaWrite(11,    0, ea,size,0x0007,1);\r
691 \r
692   opend_op_changes_cycles = (count<0);\r
693   OpEnd(ea,0);\r
694 \r
695   return 0;\r
696 }\r
697 \r
698 // Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee \r
699 int OpAsrEa(int op)\r
700 {\r
701   int use=0,type=0,dir=0,ea=0,size=1;\r
702 \r
703   type=(op>>9)&3;\r
704   dir =(op>>8)&1;\r
705   ea  = op&0x3f;\r
706 \r
707   if (ea<0x10) return 1;\r
708   // See if we can do this opcode:\r
709   if (EaCanRead(ea,0)==0) return 1;\r
710   if (EaCanWrite(ea)==0) return 1;\r
711 \r
712   use=OpBase(op,size);\r
713   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
714 \r
715   OpStart(op,ea); Cycles=6; // EmitAsr() will add 2\r
716 \r
717   EaCalc (11,0x003f,ea,size,1);\r
718   EaRead (11,     0,ea,size,0x003f,1);\r
719 \r
720   EmitAsr(op,type,dir,1,size,0);\r
721 \r
722   EaWrite(11,     0,ea,size,0x003f,1);\r
723 \r
724   OpEnd(ea);\r
725   return 0;\r
726 }\r
727 \r
728 int OpTas(int op, int gen_special)\r
729 {\r
730   int ea=0;\r
731   int use=0;\r
732 \r
733   ea=op&0x003f;\r
734 \r
735   // See if we can do this opcode:\r
736   if (EaCanWrite(ea)==0 || EaAn(ea)) return 1;\r
737 \r
738   use=OpBase(op,0);\r
739   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
740 \r
741   if (!gen_special) OpStart(op,ea);\r
742   else\r
743     ot("Op%.4x_%s\n", op, ms?"":":");\r
744 \r
745   Cycles=4;\r
746   if(ea>=8) Cycles+=10;\r
747 \r
748   EaCalc (11,0x003f,ea,0,1);\r
749   EaRead (11,     1,ea,0,0x003f,1);\r
750 \r
751   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
752   OpGetFlags(0,0);\r
753   ot("\n");\r
754 \r
755 #if CYCLONE_FOR_GENESIS\r
756   // the original Sega hardware ignores write-back phase (to memory only)\r
757   if (ea < 0x10 || gen_special) {\r
758 #endif\r
759     ot("  orr r1,r1,#0x80000000 ;@ set bit7\n");\r
760 \r
761     EaWrite(11,     1,ea,0,0x003f,1);\r
762 #if CYCLONE_FOR_GENESIS\r
763   }\r
764 #endif\r
765 \r
766   OpEnd(ea);\r
767 \r
768 #if (CYCLONE_FOR_GENESIS == 2)\r
769   if (!gen_special && ea >= 0x10) {\r
770     OpTas(op, 1);\r
771   }\r
772 #endif\r
773 \r
774   return 0;\r
775 }\r
776 \r