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