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