some optimizations
[picodrive.git] / cpu / Cyclone / OpArith.cpp
1 \r
2 #include "app.h"\r
3 \r
4 // --------------------- Opcodes 0x0000+ ---------------------\r
5 // Emit an Ori/And/Sub/Add/Eor/Cmp Immediate opcode, 0000ttt0 ssaaaaaa\r
6 int OpArith(int op)\r
7 {\r
8   int type=0,size=0;\r
9   int sea=0,tea=0;\r
10   int use=0;\r
11   char *shiftstr="";\r
12 \r
13   // Get source and target EA\r
14   type=(op>>9)&7; if (type==4 || type>=7) return 1;\r
15   size=(op>>6)&3; if (size>=3) return 1;\r
16   sea=   0x003c;\r
17   tea=op&0x003f;\r
18 \r
19   // See if we can do this opcode:\r
20   if (EaCanRead(tea,size)==0) return 1;\r
21   if (EaCanWrite(tea)==0 || EaAn(tea)) return 1;\r
22 \r
23   use=OpBase(op);\r
24   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
25 \r
26   OpStart(op, sea, tea); Cycles=4;\r
27 \r
28   EaCalc(10,0x0000, sea,size,1);\r
29   EaCalc(11,0x003f, tea,size,1);\r
30   EaRead(10,    10, sea,size,0,0,0);\r
31   EaRead(11,     0, tea,size,0x003f,1);\r
32 \r
33   if (size==0) shiftstr=",asl #24";\r
34   else if (size==1) shiftstr=",asl #16";\r
35 \r
36   ot(";@ Do arithmetic:\n");\r
37 \r
38   if (type==0) ot("  orr r1,r0,r10%s\n",shiftstr);\r
39   if (type==1) ot("  and r1,r0,r10%s\n",shiftstr);\r
40   if (type==2) ot("  subs r1,r0,r10%s ;@ Defines NZCV\n",shiftstr);\r
41   if (type==3) ot("  adds r1,r0,r10%s ;@ Defines NZCV\n",shiftstr);\r
42   if (type==5) ot("  eor r1,r0,r10%s\n",shiftstr);\r
43   if (type==6) ot("  cmp r0,r10%s ;@ Defines NZCV\n",shiftstr);\r
44 \r
45   if (type<2 || type==5) ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); // 0,1,5\r
46 \r
47   if (type< 2) OpGetFlags(0,0); // Ori/And\r
48   if (type==2) OpGetFlags(1,1); // Sub: Subtract/X-bit\r
49   if (type==3) OpGetFlags(0,1); // Add: X-bit\r
50   if (type==5) OpGetFlags(0,0); // Eor\r
51   if (type==6) OpGetFlags(1,0); // Cmp: Subtract\r
52   ot("\n");\r
53 \r
54   if (type!=6)\r
55   {\r
56     EaWrite(11, 1, tea,size,0x003f,1);\r
57   }\r
58 \r
59   // Correct cycles:\r
60   if (type==6)\r
61   {\r
62     if (size>=2 && tea<0x10) Cycles+=2;\r
63   }\r
64   else\r
65   {\r
66     if (size>=2) Cycles+=4;\r
67     if (tea>=8)  Cycles+=4;\r
68     if (type==1 && size>=2 && tea<8) Cycles-=2;\r
69   }\r
70 \r
71   OpEnd(sea,tea);\r
72 \r
73   return 0;\r
74 }\r
75 \r
76 // --------------------- Opcodes 0x5000+ ---------------------\r
77 int OpAddq(int op)\r
78 {\r
79   // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA)\r
80   int num=0,type=0,size=0,ea=0;\r
81   int use=0;\r
82   char count[16]="";\r
83   int shift=0;\r
84 \r
85   num =(op>>9)&7; if (num==0) num=8;\r
86   type=(op>>8)&1;\r
87   size=(op>>6)&3; if (size>=3) return 1;\r
88   ea  = op&0x3f;\r
89 \r
90   // See if we can do this opcode:\r
91   if (EaCanRead (ea,size)==0) return 1;\r
92   if (EaCanWrite(ea)     ==0) return 1;\r
93   if (size == 0 && EaAn(ea) ) return 1;\r
94 \r
95   use=OpBase(op,1);\r
96 \r
97   if (num!=8) use|=0x0e00; // If num is not 8, use same handler\r
98   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
99 \r
100   OpStart(op,ea);\r
101   Cycles=ea<8?4:8;\r
102   if(type==0&&size==1) Cycles=ea<0x10?4:8;\r
103   if(size>=2) Cycles=ea<0x10?8:12;\r
104 \r
105   if (size>0 && (ea&0x38)==0x08) size=2; // addq.w #n,An is also 32-bit\r
106 \r
107   EaCalc(10,0x003f, ea,size,1);\r
108   EaRead(10,     0, ea,size,0x003f,1);\r
109 \r
110   shift=32-(8<<size);\r
111 \r
112   if (num!=8)\r
113   {\r
114     int lsr=9-shift;\r
115 \r
116     if (lsr>=0) ot("  mov r2,r8,lsr #%d ;@ Get quick value\n", lsr);\r
117     else        ot("  mov r2,r8,lsl #%d ;@ Get quick value\n",-lsr);\r
118 \r
119     ot("  and r2,r2,#0x%.4x\n",7<<shift);\r
120     ot("\n");\r
121     strcpy(count,"r2");\r
122   }\r
123 \r
124   if (num==8) sprintf(count,"#0x%.4x",8<<shift);\r
125 \r
126   if (type==0) ot("  adds r1,r0,%s\n",count);\r
127   if (type==1) ot("  subs r1,r0,%s\n",count);\r
128 \r
129   if ((ea&0x38)!=0x08) OpGetFlags(type,1);\r
130   ot("\n");\r
131 \r
132   EaWrite(10,     1, ea,size,0x003f,1);\r
133 \r
134   OpEnd(ea);\r
135 \r
136   return 0;\r
137 }\r
138 \r
139 // --------------------- Opcodes 0x8000+ ---------------------\r
140 // 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA)\r
141 int OpArithReg(int op)\r
142 {\r
143   int use=0;\r
144   int type=0,size=0,dir=0,rea=0,ea=0;\r
145 \r
146   type=(op>>12)&5;\r
147   rea =(op>> 9)&7;\r
148   dir =(op>> 8)&1; // er,re\r
149   size=(op>> 6)&3; if (size>=3) return 1;\r
150   ea  = op&0x3f;\r
151 \r
152   if (dir && ea<0x10) return 1; // addx/subx opcode\r
153 \r
154   // See if we can do this opcode:\r
155   if (dir==0 && EaCanRead (ea,size)==0) return 1;\r
156   if (dir    && EaCanWrite(ea)==0)      return 1;\r
157   if ((size==0||!(type&1))&&EaAn(ea))   return 1;\r
158 \r
159   use=OpBase(op);\r
160   use&=~0x0e00; // Use same opcode for Dn\r
161   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
162 \r
163   OpStart(op,ea); Cycles=4;\r
164 \r
165   ot(";@ Get r10=EA r11=EA value\n");\r
166   EaCalc(10,0x003f, ea,size,1);\r
167   EaRead(10,    11, ea,size,0x003f,1);\r
168   ot(";@ Get r0=Register r1=Register value\n");\r
169   EaCalc( 0,0x0e00,rea,size,1);\r
170   EaRead( 0,     1,rea,size,0x0e00,1);\r
171 \r
172   ot(";@ Do arithmetic:\n");\r
173   if (type==0) ot("  orr  ");\r
174   if (type==1) ot("  subs ");\r
175   if (type==4) ot("  and  ");\r
176   if (type==5) ot("  adds ");\r
177   if (dir) ot("r1,r11,r1\n");\r
178   else     ot("r1,r1,r11\n");\r
179 \r
180   if ((type&1)==0) ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
181 \r
182   OpGetFlags(type==1,type&1); // 1==subtract\r
183   ot("\n");\r
184 \r
185   ot(";@ Save result:\n");\r
186   if (dir) EaWrite(10, 1, ea,size,0x003f,1);\r
187   else     EaWrite( 0, 1,rea,size,0x0e00,1);\r
188 \r
189   if(rea==ea) {\r
190     if(ea<8) Cycles=(size>=2)?8:4; else Cycles+=(size>=2)?26:14;\r
191   } else if(dir) {\r
192     Cycles+=4;\r
193     if(size>=2) Cycles+=4;\r
194   } else {\r
195     if(size>=2) {\r
196       Cycles+=2;\r
197       if(ea<0x10||ea==0x3c) Cycles+=2;\r
198     }\r
199   }\r
200 \r
201   OpEnd(ea);\r
202 \r
203   return 0;\r
204 }\r
205 \r
206 // --------------------- Opcodes 0x80c0+ ---------------------\r
207 int OpMul(int op)\r
208 {\r
209   // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA)\r
210   int type=0,rea=0,sign=0,ea=0;\r
211   int use=0;\r
212 \r
213   type=(op>>14)&1; // div/mul\r
214   rea =(op>> 9)&7;\r
215   sign=(op>> 8)&1;\r
216   ea  = op&0x3f;\r
217 \r
218   // See if we can do this opcode:\r
219   if (EaCanRead(ea,1)==0||EaAn(ea)) return 1;\r
220 \r
221   use=OpBase(op);\r
222   use&=~0x0e00; // Use same for all registers\r
223   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
224 \r
225   OpStart(op,ea);\r
226   if(type) Cycles=54;\r
227   else     Cycles=sign?158:140;\r
228 \r
229   EaCalc(10,0x003f, ea, 1);\r
230   EaRead(10,    10, ea, 1,0x003f);\r
231 \r
232   EaCalc (0,0x0e00,rea, 2,1);\r
233   EaRead (0,     2,rea, 2,0x0e00,1);\r
234 \r
235   if (type==0) // div\r
236   {\r
237     // the manual says C is always cleared, but neither Musashi nor FAME do that\r
238     //ot("  bic r9,r9,#0x20000000 ;@ always clear C\n");\r
239     ot("  tst r10,r10\n");\r
240     ot("  beq divzero%.4x ;@ division by zero\n",op);\r
241     ot("\n");\r
242     \r
243     if (sign)\r
244     {\r
245       ot("  mov r11,#0 ;@ r11 = 1 or 2 if the result is negative\n");\r
246       ot("  orrmi r11,r11,#1\n");\r
247       ot("  rsbmi r10,r10,#0 ;@ Make r10 positive\n");\r
248       ot("\n");\r
249       ot("  tst r2,r2\n");\r
250       ot("  orrmi r11,r11,#2\n");\r
251       ot("  rsbmi r2,r2,#0 ;@ Make r2 positive\n");\r
252       ot("\n");\r
253     }\r
254     else\r
255     {\r
256       ot("  mov r10,r10,lsl #16 ;@ use only 16 bits of divisor\n");\r
257       ot("  mov r10,r10,lsr #16\n");\r
258     }\r
259 \r
260     ot(";@ Divide r2 by r10\n");\r
261     ot("  mov r3,#0\n");\r
262     ot("  mov r1,r10\n");\r
263     ot("\n");\r
264     ot(";@ Shift up divisor till it's just less than numerator\n");\r
265     ot("Shift%.4x%s\n",op,ms?"":":");\r
266     ot("  cmp r1,r2,lsr #1\n");\r
267     ot("  movls r1,r1,lsl #1\n");\r
268     ot("  bcc Shift%.4x\n",op);\r
269     ot("\n");\r
270 \r
271     ot("Divide%.4x%s\n",op,ms?"":":");\r
272     ot("  cmp r2,r1\n");\r
273     ot("  adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n");\r
274     ot("  subcs r2,r2,r1\n");\r
275     ot("  teq r1,r10\n");\r
276     ot("  movne r1,r1,lsr #1\n");\r
277     ot("  bne Divide%.4x\n",op);\r
278     ot("\n");\r
279     ot(";@r3==quotient,r2==remainder\n");\r
280 \r
281     if (sign)\r
282     {\r
283       // sign correction\r
284       ot("  and r1,r11,#1\n");\r
285       ot("  teq r1,r11,lsr #1\n");\r
286       ot("  rsbne r3,r3,#0 ;@ negate if quotient is negative\n");\r
287       ot("  tst r11,#2\n");\r
288       ot("  rsbne r2,r2,#0 ;@ negate the remainder if divident was negative\n");\r
289       ot("\n");\r
290 \r
291       // signed overflow check\r
292       ot("  mov r1,r3,asl #16\n");\r
293       ot("  cmp r3,r1,asr #16 ;@ signed overflow?\n");\r
294       ot("  orrne r9,r9,#0x10000000 ;@ set overflow flag\n");\r
295       ot("  bne endofop%.4x ;@ overflow!\n",op);\r
296     }\r
297     else\r
298     {\r
299       // overflow check\r
300       ot("  movs r1,r3,lsr #16 ;@ check for overflow condition\n");\r
301       ot("  orrne r9,r9,#0x10000000 ;@ set overflow flag\n");\r
302       ot("  bne endofop%.4x ;@ overflow!\n",op);\r
303     }\r
304 \r
305     ot("  mov r1,r3,lsl #16 ;@ Clip to 16-bits\n");\r
306     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
307     OpGetFlags(0,0);\r
308 \r
309     ot("  mov r1,r1,lsr #16\n");\r
310     ot("  orr r1,r1,r2,lsl #16 ;@ Insert remainder\n");\r
311   }\r
312 \r
313   if (type==1)\r
314   {\r
315     char *shift="asr";\r
316 \r
317     ot(";@ Get 16-bit signs right:\n");\r
318     if (sign==0) { ot("  mov r10,r10,lsl #16\n"); shift="lsr"; }\r
319     ot("  mov r2,r2,lsl #16\n");\r
320 \r
321     if (sign==0) ot("  mov r10,r10,lsr #16\n");\r
322     ot("  mov r2,r2,%s #16\n",shift);\r
323     ot("\n");\r
324 \r
325     ot("  mul r1,r2,r10\n");\r
326     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
327     OpGetFlags(0,0);\r
328   }\r
329   ot("\n");\r
330 \r
331   EaWrite(0,     1,rea, 2,0x0e00,1);\r
332 \r
333   ot("endofop%.4x%s\n",op,ms?"":":");\r
334   OpEnd(ea);\r
335 \r
336   ot("divzero%.4x%s\n",op,ms?"":":");\r
337   ot("  mov r0,#0x14 ;@ Divide by zero\n");\r
338   ot("  bl Exception\n");\r
339   Cycles+=38;\r
340   OpEnd(ea);\r
341   ot("\n");\r
342 \r
343   return 0;\r
344 }\r
345 \r
346 // Get X Bit into carry - trashes r2\r
347 int GetXBit(int subtract)\r
348 {\r
349   ot(";@ Get X bit:\n");\r
350   ot("  ldrb r2,[r7,#0x45]\n");\r
351   if (subtract) ot("  mvn r2,r2,lsl #28 ;@ Invert it\n");\r
352   else          ot("  mov r2,r2,lsl #28\n");\r
353   ot("  msr cpsr_flg,r2 ;@ Get into Carry\n");\r
354   ot("\n");\r
355   return 0;\r
356 }\r
357 \r
358 // --------------------- Opcodes 0x8100+ ---------------------\r
359 // 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad)\r
360 int OpAbcd(int op)\r
361 {\r
362   int use=0;\r
363   int type=0,sea=0,addr=0,dea=0;\r
364   \r
365   type=(op>>14)&1; // sbcd/abcd\r
366   dea =(op>> 9)&7;\r
367   addr=(op>> 3)&1;\r
368   sea = op     &7;\r
369 \r
370   if (addr) { sea|=0x20; dea|=0x20; }\r
371 \r
372   use=op&~0x0e07; // Use same opcode for all registers..\r
373   if (sea==0x27||dea==0x27) use=op; // ..except -(a7)\r
374   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
375 \r
376   OpStart(op,sea,dea); Cycles=6;\r
377 \r
378   EaCalc( 0,0x0007, sea,0,1);\r
379   EaRead( 0,    10, sea,0,0x0007,1);\r
380   EaCalc(11,0x0e00, dea,0,1);\r
381   EaRead(11,     1, dea,0,0x0e00,1);\r
382 \r
383   ot("  bic r9,r9,#0xb1000000 ;@ clear all flags except old Z\n");\r
384 \r
385   if (type)\r
386   {\r
387     ot("  ldrb r0,[r7,#0x45] ;@ Get X bit\n");\r
388     ot("  mov r3,#0x00f00000\n");\r
389     ot("  and r2,r3,r1,lsr #4\n");\r
390     ot("  tst r0,#2\n");\r
391     ot("  and r0,r3,r10,lsr #4\n");\r
392     ot("  add r0,r0,r2\n");\r
393     ot("  addne r0,r0,#0x00100000\n");\r
394 //    ot("  tst r0,#0x00800000\n");\r
395 //    ot("  orreq r9,r9,#0x01000000 ;@ Undefined V behavior\n");\r
396     ot("  cmp r0,#0x00900000\n");\r
397     ot("  addhi r0,r0,#0x00600000 ;@ Decimal adjust units\n");\r
398 \r
399     ot("  mov r2,r1,lsr #28\n");\r
400     ot("  add r0,r0,r2,lsl #24\n");\r
401     ot("  mov r2,r10,lsr #28\n");\r
402     ot("  add r0,r0,r2,lsl #24\n");\r
403     ot("  cmp r0,#0x09900000\n");\r
404     ot("  orrhi r9,r9,#0x20000000 ;@ C\n");\r
405     ot("  subhi r0,r0,#0x0a000000\n");\r
406 //    ot("  and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n");\r
407 //    ot("  orr r9,r9,r3,lsl #4 ;@ V\n");\r
408     ot("  movs r0,r0,lsl #4\n");\r
409     ot("  orrmi r9,r9,#0x90000000 ;@ Undefined N+V behavior\n"); // this is what Musashi really does\r
410     ot("  bicne r9,r9,#0x40000000 ;@ Z flag\n");\r
411   }\r
412   else\r
413   {\r
414     ot("  ldrb r0,[r7,#0x45] ;@ Get X bit\n");\r
415     ot("  mov r3,#0x00f00000\n");\r
416     ot("  and r2,r3,r10,lsr #4\n");\r
417     ot("  tst r0,#2\n");\r
418     ot("  and r0,r3,r1,lsr #4\n");\r
419     ot("  sub r0,r0,r2\n");\r
420     ot("  subne r0,r0,#0x00100000\n");\r
421 //    ot("  tst r0,#0x00800000\n");\r
422 //    ot("  orreq r9,r9,#0x01000000 ;@ Undefined V behavior\n");\r
423     ot("  cmp r0,#0x00900000\n");\r
424     ot("  subhi r0,r0,#0x00600000 ;@ Decimal adjust units\n");\r
425 \r
426     ot("  mov r2,r1,lsr #28\n");\r
427     ot("  add r0,r0,r2,lsl #24\n");\r
428     ot("  mov r2,r10,lsr #28\n");\r
429     ot("  sub r0,r0,r2,lsl #24\n");\r
430     ot("  cmp r0,#0x09900000\n");\r
431     ot("  orrhi r9,r9,#0xa0000000 ;@ N and C\n");\r
432     ot("  addhi r0,r0,#0x0a000000\n");\r
433 //    ot("  and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n");\r
434 //    ot("  orr r9,r9,r3,lsl #4 ;@ V\n");\r
435     ot("  movs r0,r0,lsl #4\n");\r
436 //    ot("  orrmi r9,r9,#0x80000000 ;@ Undefined N behavior\n");\r
437     ot("  bicne r9,r9,#0x40000000 ;@ Z flag\n");\r
438   }\r
439 \r
440   ot("  mov r2,r9,lsr #28\n");\r
441   ot("  strb r2,[r7,#0x45] ;@ Save X bit\n");\r
442 \r
443   EaWrite(11,     0, dea,0,0x0e00,1);\r
444   OpEnd(sea,dea);\r
445 \r
446   return 0;\r
447 }\r
448 \r
449 // 01008000 00eeeeee - nbcd <ea>\r
450 int OpNbcd(int op)\r
451 {\r
452   int use=0;\r
453   int ea=0;\r
454   \r
455   ea=op&0x3f;\r
456 \r
457   if(EaCanWrite(ea)==0||EaAn(ea)) return 1;\r
458 \r
459   use=OpBase(op);\r
460   if(op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
461 \r
462   OpStart(op,ea); Cycles=6;\r
463   if(ea >= 8)  Cycles+=2;\r
464 \r
465   EaCalc(10,0x3f, ea,0,1);\r
466   EaRead(10,   0, ea,0,0x3f,1);\r
467 \r
468   // this is rewrite of Musashi's code\r
469   ot("  ldrb r2,[r7,#0x45]\n");\r
470   ot("  tst r2,#2\n");\r
471   ot("  mov r2,r0\n");\r
472   ot("  addne r2,r0,#0x01000000 ;@ add X\n");\r
473   ot("  rsbs r1,r2,#0x9a000000 ;@ do arithmetic\n");\r
474 \r
475   ot("  bic r9,r9,#0xb0000000 ;@ clear all flags, except Z\n");\r
476   ot("  orrmi r9,r9,#0x80000000 ;@ N\n");\r
477   ot("  cmp r1,#0x9a000000\n");\r
478   ot("  beq finish%.4x\n",op);\r
479   ot("\n");\r
480 \r
481   ot("  mvn r3,r9,lsr #3 ;@ Undefined V behavior\n",op);\r
482   ot("  and r2,r1,#0x0f000000\n");\r
483   ot("  cmp r2,#0x0a000000\n");\r
484   ot("  andeq r1,r1,#0xf0000000\n");\r
485   ot("  addeq r1,r1,#0x10000000\n");\r
486   ot("  and r3,r3,r1,lsr #3 ;@ Undefined V behavior part II\n",op);\r
487   ot("  tst r1,r1\n");\r
488   ot("  orr r9,r9,r3 ;@ save V\n",op);\r
489   ot("  bicne r9,r9,#0x40000000 ;@ Z\n");\r
490   ot("  orr r9,r9,#0x20000000 ;@ C\n");\r
491   ot("\n");\r
492 \r
493   EaWrite(10,     1, ea,0,0x3f,1);\r
494 \r
495   ot("finish%.4x%s\n",op,ms?"":":");\r
496   ot("  mov r2,r9,lsr #28\n");\r
497   ot("  strb r2, [r7,#0x45]\n");\r
498 \r
499   OpEnd(ea);\r
500 \r
501   return 0;\r
502 }\r
503 \r
504 // --------------------- Opcodes 0x90c0+ ---------------------\r
505 // Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA)\r
506 int OpAritha(int op)\r
507 {\r
508   int use=0;\r
509   int type=0,size=0,sea=0,dea=0;\r
510 \r
511   // Suba/Cmpa/Adda/(invalid):\r
512   type=(op>>13)&3; if (type>=3) return 1;\r
513 \r
514   size=(op>>8)&1; size++;\r
515   dea=(op>>9)&7; dea|=8; // Dest=An\r
516   sea=op&0x003f; // Source\r
517 \r
518   // See if we can do this opcode:\r
519   if (EaCanRead(sea,size)==0) return 1;\r
520 \r
521   use=OpBase(op);\r
522   use&=~0x0e00; // Use same opcode for An\r
523   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
524 \r
525   OpStart(op,sea); Cycles=(size==2)?6:8;\r
526   if(size==2&&(sea<0x10||sea==0x3c)) Cycles+=2;\r
527   if(type==1) Cycles=6;\r
528 \r
529   \r
530   // must calculate reg EA first, because of situations like: suba.w (A0)+, A0\r
531   EaCalc (10,0x0e00, dea,2,1);\r
532   EaRead (10,    11, dea,2,0x0e00);\r
533 \r
534   EaCalc ( 0,0x003f, sea,size);\r
535   EaRead ( 0,     0, sea,size,0x003f);\r
536 \r
537   if (type==0) ot("  sub r11,r11,r0\n");\r
538   if (type==1) ot("  cmp r11,r0 ;@ Defines NZCV\n");\r
539   if (type==1) OpGetFlags(1,0); // Get Cmp flags\r
540   if (type==2) ot("  add r11,r11,r0\n");\r
541   ot("\n");\r
542   \r
543   if (type!=1) EaWrite(10,    11, dea,2,0x0e00,1);\r
544 \r
545   OpEnd(sea);\r
546 \r
547   return 0;\r
548 }\r
549 \r
550 // --------------------- Opcodes 0x9100+ ---------------------\r
551 // Emit a Subx/Addx opcode, 1t01ddd1 zz00rsss addx.z Ds,Dd\r
552 int OpAddx(int op)\r
553 {\r
554   int use=0;\r
555   int type=0,size=0,dea=0,sea=0,mem=0;\r
556 \r
557   type=(op>>12)&5;\r
558   dea =(op>> 9)&7;\r
559   size=(op>> 6)&3; if (size>=3) return 1;\r
560   sea = op&7;\r
561   mem =(op>> 3)&1;\r
562 \r
563   // See if we can do this opcode:\r
564   if (EaCanRead(sea,size)==0) return 1;\r
565   if (EaCanWrite(dea)==0) return 1;\r
566 \r
567   if(mem) { sea+=0x20; dea+=0x20; }\r
568 \r
569   use=op&~0x0e07; // Use same opcode for Dn\r
570   if (size==0&&(sea==0x27||dea==0x27)) use=op; // ___x.b -(a7)\r
571   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
572 \r
573   OpStart(op,sea,dea); Cycles=4;\r
574   if(size>=2)   Cycles+=4;\r
575   if(sea>=0x10) Cycles+=2;\r
576 \r
577   ot(";@ Get r10=EA r11=EA value\n");\r
578   EaCalc( 0,0x0007,sea,size,1);\r
579   EaRead( 0,    11,sea,size,0x0007,1);\r
580   ot(";@ Get r0=Register r1=Register value\n");\r
581   EaCalc( 0,0x0e00,dea,size,1);\r
582   EaRead( 0,     1,dea,size,0x0e00,1);\r
583 \r
584   ot(";@ Do arithmetic:\n");\r
585   GetXBit(type==1);\r
586 \r
587   if (type==5 && size<2)\r
588   {\r
589     ot(";@ Make sure the carry bit will tip the balance:\n");\r
590     ot("  mvn r2,#0\n");\r
591     ot("  orr r11,r11,r2,lsr #%i\n",(size==0)?8:16);\r
592     ot("\n");\r
593   }\r
594 \r
595   if (type==1) ot("  sbcs r1,r1,r11\n");\r
596   if (type==5) ot("  adcs r1,r1,r11\n");\r
597   ot("  orr r3,r9,#0xb0000000 ;@ for old Z\n");\r
598   OpGetFlags(type==1,1,0); // subtract\r
599   if (size<2) {\r
600     ot("  movs r2,r1,lsr #%i\n", size?16:24);\r
601     ot("  orreq r9,r9,#0x40000000 ;@ add potentially missed Z\n");\r
602   }\r
603   ot("  andeq r9,r9,r3 ;@ fix Z\n");\r
604   ot("\n");\r
605 \r
606   ot(";@ Save result:\n");\r
607   EaWrite( 0, 1, dea,size,0x0e00,1);\r
608 \r
609   OpEnd(sea,dea);\r
610 \r
611   return 0;\r
612 }\r
613 \r
614 // --------------------- Opcodes 0xb000+ ---------------------\r
615 // Emit a Cmp/Eor opcode, 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea)\r
616 int OpCmpEor(int op)\r
617 {\r
618   int rea=0,eor=0;\r
619   int size=0,ea=0,use=0;\r
620 \r
621   // Get EA and register EA\r
622   rea=(op>>9)&7;\r
623   eor=(op>>8)&1;\r
624   size=(op>>6)&3; if (size>=3) return 1;\r
625   ea=op&0x3f;\r
626 \r
627   if (eor && (ea>>3) == 1) return 1; // not a valid mode for eor\r
628 \r
629   // See if we can do this opcode:\r
630   if (EaCanRead(ea,size)==0) return 1;\r
631   if (eor && EaCanWrite(ea)==0) return 1;\r
632   if (EaAn(ea)&&(eor||size==0)) return 1;\r
633 \r
634   use=OpBase(op);\r
635   use&=~0x0e00; // Use 1 handler for register d0-7\r
636   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
637 \r
638   OpStart(op,ea); Cycles=4;\r
639   if(eor) {\r
640     if(ea>8)     Cycles+=4;\r
641     if(size>=2)  Cycles+=4;\r
642   } else {\r
643     if(size>=2)  Cycles+=2;\r
644   }\r
645 \r
646   ot(";@ Get EA into r10 and value into r0:\n");\r
647   EaCalc (10,0x003f,  ea,size,1);\r
648   EaRead (10,     0,  ea,size,0x003f,1);\r
649 \r
650   ot(";@ Get register operand into r1:\n");\r
651   EaCalc (1, 0x0e00, rea,size,1);\r
652   EaRead (1,      1, rea,size,0x0e00,1);\r
653 \r
654   ot(";@ Do arithmetic:\n");\r
655   if (eor==0) ot("  cmp r1,r0\n");\r
656   if (eor)\r
657   {\r
658     ot("  eor r1,r0,r1\n");\r
659     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
660   }\r
661 \r
662   OpGetFlags(eor==0,0); // Cmp like subtract\r
663   ot("\n");\r
664 \r
665   if (eor) EaWrite(10, 1,ea,size,0x003f,1);\r
666 \r
667   OpEnd(ea);\r
668   return 0;\r
669 }\r
670 \r
671 // Emit a Cmpm opcode, 1011ddd1 xx001sss (rrr=Adst, xx=size extension, sss=Asrc)\r
672 int OpCmpm(int op)\r
673 {\r
674   int size=0,sea=0,dea=0,use=0;\r
675 \r
676   // get size, get EAs\r
677   size=(op>>6)&3; if (size>=3) return 1;\r
678   sea=(op&7)|0x18;\r
679   dea=(op>>9)&0x3f;\r
680 \r
681   use=op&~0x0e07; // Use 1 handler for all registers..\r
682   if (size==0&&(sea==0x1f||dea==0x1f)) use=op; // ..except (a7)+\r
683   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
684 \r
685   OpStart(op,sea); Cycles=4;\r
686 \r
687   ot(";@ Get src operand into r10:\n");\r
688   EaCalc (0,0x000f, sea,size,1);\r
689   EaRead (0,    10, sea,size,0x000f,1);\r
690 \r
691   ot(";@ Get dst operand into r0:\n");\r
692   EaCalc (0,0x1e00, dea,size,1);\r
693   EaRead (0,     0, dea,size,0x1e00,1);\r
694 \r
695   ot("  cmp r0,r10\n");\r
696   OpGetFlags(1,0); // Cmp like subtract\r
697 \r
698   OpEnd(sea);\r
699   return 0;\r
700 }\r
701 \r
702 \r
703 // Emit a Chk opcode, 0100ddd1 x0eeeeee (rrr=Dn, x=size extension, eeeeee=ea)\r
704 int OpChk(int op)\r
705 {\r
706   int rea=0;\r
707   int size=0,ea=0,use=0;\r
708 \r
709   // Get EA and register EA\r
710   rea=(op>>9)&7;\r
711   if((op>>7)&1)\r
712        size=1; // word operation\r
713   else size=2; // long\r
714   ea=op&0x3f;\r
715 \r
716   if (EaAn(ea)) return 1; // not a valid mode\r
717   if (size!=1)  return 1; // 000 variant only supports word\r
718 \r
719   // See if we can do this opcode:\r
720   if (EaCanRead(ea,size)==0) return 1;\r
721 \r
722   use=OpBase(op);\r
723   use&=~0x0e00; // Use 1 handler for register d0-7\r
724   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
725 \r
726   OpStart(op,ea); Cycles=10;\r
727 \r
728   ot(";@ Get EA into r10 and value into r0:\n");\r
729   EaCalc (10,0x003f,  ea,size,1);\r
730   EaRead (10,     0,  ea,size,0x003f,1);\r
731 \r
732   ot(";@ Get register operand into r1:\n");\r
733   EaCalc (1, 0x0e00, rea,size,1);\r
734   EaRead (1,      1, rea,size,0x0e00,1);\r
735 \r
736   ot(";@ get flags, including undocumented ones\n");\r
737   ot("  and r3,r9,#0x80000000\n");\r
738   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
739   OpGetFlags(0,0);\r
740 \r
741   ot(";@ is reg negative?\n");\r
742   ot("  bmi chktrap%.4x\n",op);\r
743 \r
744   ot(";@ Do arithmetic:\n");\r
745   ot("  cmp r1,r0\n");\r
746   ot("  bicgt r9,r9,#0x80000000 ;@ N\n");\r
747   ot("  bgt chktrap%.4x\n",op);\r
748 \r
749   ot(";@ old N remains\n");\r
750   ot("  bic r9,r9,#0x80000000 ;@ N\n");\r
751   ot("  orr r9,r9,r3\n");\r
752   OpEnd(ea);\r
753 \r
754   ot("chktrap%.4x%s ;@ CHK exception:\n",op,ms?"":":");\r
755   ot("  mov r0,#0x18\n");\r
756   ot("  bl Exception\n");\r
757   Cycles+=40;\r
758   OpEnd(ea);\r
759 \r
760   return 0;\r
761 }\r
762 \r