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