a2e30a21a0e0a7bdaceb34c74a214a0cdc507593
[cyclone68000.git] / Cyclone / OpLogic.cpp
1 \r
2 // This file is part of the Cyclone 68000 Emulator\r
3 \r
4 // This code is licensed under the GNU General Public License version 2.0 and the MAME License.\r
5 // You can choose the license that has the most advantages for you.\r
6 \r
7 // SVN repository can be found at http://code.google.com/p/cyclone68000/\r
8 \r
9 #include "app.h"\r
10 \r
11 // --------------------- Opcodes 0x0100+ ---------------------\r
12 // Emit a Btst (Register) opcode 0000nnn1 00aaaaaa\r
13 int OpBtstReg(int op)\r
14 {\r
15   int use=0;\r
16   int type=0,sea=0,tea=0;\r
17   int size=0;\r
18 \r
19   type=(op>>6)&3;\r
20   // Get source and target EA\r
21   sea=(op>>9)&7;\r
22   tea=op&0x003f;\r
23   if (tea<0x10) size=2; // For registers, 32-bits\r
24 \r
25   if ((tea&0x38)==0x08) return 1; // movep\r
26 \r
27   // See if we can do this opcode:\r
28   if (EaCanRead(tea,0)==0) return 1;\r
29   if (type>0)\r
30   {\r
31     if (EaCanWrite(tea)==0) return 1;\r
32   }\r
33 \r
34   use=OpBase(op);\r
35   use&=~0x0e00; // Use same handler for all registers\r
36   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
37 \r
38   OpStart(op); Cycles=4;\r
39   if (tea<0x10) Cycles+=2;\r
40   if (type>0) Cycles+=4;\r
41 \r
42   ot("  mov r10,#1\n");\r
43 \r
44   EaCalc (0,0x0e00,sea,0);\r
45   EaRead (0,     0,sea,0);\r
46   ot("  bic r9,r9,#0x40000000 ;@ Blank Z flag\n");\r
47   ot("  mov r10,r10,lsl r0 ;@ Make bit mask\n");\r
48   ot("\n");\r
49 \r
50   EaCalc(11,0x003f,tea,size);\r
51   EaRead(11,     0,tea,size);\r
52   ot("  tst r0,r10 ;@ Do arithmetic\n");\r
53   ot("  orreq r9,r9,#0x40000000 ;@ Get Z flag\n");\r
54   ot("\n");\r
55 \r
56   if (type>0)\r
57   {\r
58     if (type==1) ot("  eor r1,r0,r10 ;@ Toggle bit\n");\r
59     if (type==2) ot("  bic r1,r0,r10 ;@ Clear bit\n");\r
60     if (type==3) ot("  orr r1,r0,r10 ;@ Set bit\n");\r
61     ot("\n");\r
62     EaWrite(11,   1,tea,size);\r
63   }\r
64   OpEnd();\r
65 \r
66   return 0;\r
67 }\r
68 \r
69 // --------------------- Opcodes 0x0800+ ---------------------\r
70 // Emit a Btst/Bchg/Bclr/Bset (Immediate) opcode 00001000 ttaaaaaa nn\r
71 int OpBtstImm(int op)\r
72 {\r
73   int type=0,sea=0,tea=0;\r
74   int use=0;\r
75   int size=0;\r
76 \r
77   type=(op>>6)&3;\r
78   // Get source and target EA\r
79   sea=   0x003c;\r
80   tea=op&0x003f;\r
81   if (tea<0x10) size=2; // For registers, 32-bits\r
82 \r
83   // See if we can do this opcode:\r
84   if (EaCanRead(tea,0)==0) return 1;\r
85   if (type>0)\r
86   {\r
87     if (EaCanWrite(tea)==0) return 1;\r
88   }\r
89 \r
90   use=OpBase(op);\r
91   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
92 \r
93   OpStart(op); Cycles=4;\r
94   if (type<3 && tea<0x10) Cycles+=2;\r
95   if (type>0) Cycles+=4;\r
96 \r
97   ot("  mov r10,#1\n");\r
98   ot("\n");\r
99   EaCalc ( 0,0x0000,sea,0);\r
100   EaRead ( 0,     0,sea,0);\r
101   ot("  bic r9,r9,#0x40000000 ;@ Blank Z flag\n");\r
102   ot("  mov r10,r10,lsl r0 ;@ Make bit mask\n");\r
103   ot("\n");\r
104 \r
105   EaCalc (11,0x003f,tea,size);\r
106   EaRead (11,     0,tea,size);\r
107   ot("  tst r0,r10 ;@ Do arithmetic\n");\r
108   ot("  orreq r9,r9,#0x40000000 ;@ Get Z flag\n");\r
109   ot("\n");\r
110 \r
111   if (type>0)\r
112   {\r
113     if (type==1) ot("  eor r1,r0,r10 ;@ Toggle bit\n");\r
114     if (type==2) ot("  bic r1,r0,r10 ;@ Clear bit\n");\r
115     if (type==3) ot("  orr r1,r0,r10 ;@ Set bit\n");\r
116     ot("\n");\r
117     EaWrite(11,   1,tea,size);\r
118   }\r
119 \r
120   OpEnd();\r
121 \r
122   return 0;\r
123 }\r
124 \r
125 // --------------------- Opcodes 0x4000+ ---------------------\r
126 int OpNeg(int op)\r
127 {\r
128   // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA)\r
129   int type=0,size=0,ea=0,use=0;\r
130 \r
131   type=(op>>9)&3;\r
132   ea  =op&0x003f;\r
133   size=(op>>6)&3; if (size>=3) return 1;\r
134 \r
135   switch (type)\r
136   {\r
137     case 1: case 2: case 3: break;\r
138     default: return 1; // todo\r
139   }\r
140 \r
141   // See if we can do this opcode:\r
142   if (EaCanRead (ea,size)==0) return 1;\r
143   if (EaCanWrite(ea     )==0) return 1;\r
144 \r
145   use=OpBase(op);\r
146   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
147 \r
148   OpStart(op); Cycles=size<2?4:6;\r
149 \r
150   EaCalc (10,0x003f,ea,size);\r
151 \r
152   if (type!=1) EaRead (10,0,ea,size); // Don't need to read for 'clr'\r
153   if (type==1) ot("\n");\r
154 \r
155   if (type==1)\r
156   {\r
157     ot(";@ Clear:\n");\r
158     ot("  mov r1,#0\n");\r
159     ot("  mov r9,#0x40000000 ;@ NZCV=0100\n");\r
160     ot("\n");\r
161   }\r
162 \r
163   if (type==2)\r
164   {\r
165     ot(";@ Neg:\n");\r
166     ot("  rsbs r1,r0,#0\n");\r
167     OpGetFlags(1,1);\r
168     ot("\n");\r
169   }\r
170 \r
171   if (type==3)\r
172   {\r
173     ot(";@ Not:\n");\r
174     ot("  mvn r1,r0\n");\r
175     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
176     OpGetFlags(0,0);\r
177     ot("\n");\r
178   }\r
179 \r
180   EaWrite(10,     1,ea,size);\r
181 \r
182   OpEnd();\r
183 \r
184   return 0;\r
185 }\r
186 \r
187 // --------------------- Opcodes 0x4840+ ---------------------\r
188 // Swap, 01001000 01000nnn swap Dn\r
189 int OpSwap(int op)\r
190 {\r
191   int ea=0,use=0;\r
192 \r
193   ea=op&7;\r
194   use=op&~0x0007; // Use same opcode for all An\r
195 \r
196   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
197 \r
198   OpStart(op); Cycles=4;\r
199 \r
200   EaCalc (10,0x0007,ea,2);\r
201   EaRead (10,     0,ea,2);\r
202 \r
203   ot("  mov r1,r0,ror #16\n");\r
204   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
205   OpGetFlags(0,0);\r
206 \r
207   EaWrite(10,     1,8,2);\r
208 \r
209   OpEnd();\r
210 \r
211   return 0;\r
212 }\r
213 \r
214 // --------------------- Opcodes 0x4a00+ ---------------------\r
215 // Emit a Tst opcode, 01001010 xxeeeeee\r
216 int OpTst(int op)\r
217 {\r
218   int sea=0;\r
219   int size=0,use=0;\r
220 \r
221   sea=op&0x003f;\r
222   size=(op>>6)&3; if (size>=3) return 1;\r
223 \r
224   // See if we can do this opcode:\r
225   if (EaCanWrite(sea)==0) return 1;\r
226 \r
227   use=OpBase(op);\r
228   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
229 \r
230   OpStart(op); Cycles=4;\r
231 \r
232   EaCalc ( 0,0x003f,sea,size);\r
233   EaRead ( 0,     0,sea,size);\r
234 \r
235   ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");\r
236   ot("  mrs r9,cpsr ;@ r9=flags\n");\r
237   ot("\n");\r
238 \r
239   OpEnd();\r
240   return 0;\r
241 }\r
242 \r
243 // --------------------- Opcodes 0x4880+ ---------------------\r
244 // Emit an Ext opcode, 01001000 1x000nnn\r
245 int OpExt(int op)\r
246 {\r
247   int ea=0;\r
248   int size=0,use=0;\r
249   int shift=0;\r
250 \r
251   ea=op&0x0007;\r
252   size=(op>>6)&1;\r
253   shift=32-(8<<size);\r
254 \r
255   use=OpBase(op);\r
256   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
257 \r
258   OpStart(op); Cycles=4;\r
259 \r
260   EaCalc (10,0x0007,ea,size+1);\r
261   EaRead (10,     0,ea,size+1);\r
262 \r
263   ot("  mov r0,r0,asl #%d\n",shift);\r
264   ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");\r
265   ot("  mrs r9,cpsr ;@ r9=flags\n");\r
266   ot("  mov r1,r0,asr #%d\n",shift);\r
267   ot("\n");\r
268 \r
269   EaWrite(10,     1,ea,size+1);\r
270 \r
271   OpEnd();\r
272   return 0;\r
273 }\r
274 \r
275 // --------------------- Opcodes 0x50c0+ ---------------------\r
276 // Emit a Set cc opcode, 0101cccc 11eeeeee\r
277 int OpSet(int op)\r
278 {\r
279   int cc=0,ea=0;\r
280   int size=0,use=0;\r
281   char *cond[16]=\r
282   {\r
283     "al","", "hi","ls","cc","cs","ne","eq",\r
284     "vc","vs","pl","mi","ge","lt","gt","le"\r
285   };\r
286 \r
287   cc=(op>>8)&15;\r
288   ea=op&0x003f;\r
289 \r
290   if ((ea&0x38)==0x08) return 1; // dbra, not scc\r
291   \r
292   // See if we can do this opcode:\r
293   if (EaCanWrite(ea)==0) return 1;\r
294 \r
295   use=OpBase(op);\r
296   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
297 \r
298   OpStart(op); Cycles=8;\r
299 \r
300   if (ea<0x10) Cycles=4;\r
301 \r
302   ot("  mov r1,#0\n");\r
303 \r
304   if (cc!=1)\r
305   {\r
306     ot(";@ Is the condition true?\n");\r
307     if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");\r
308     ot("  msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");\r
309     if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");\r
310     ot("  mvn%s r1,r1\n",cond[cc]);\r
311   }\r
312 \r
313   if (ea<0x10) ot("  sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]);\r
314   ot("\n");\r
315 \r
316   EaCalc (0,0x003f, ea,size);\r
317   EaWrite(0,     1, ea,size);\r
318 \r
319   OpEnd();\r
320   return 0;\r
321 }\r
322 \r
323 // Emit a Asr/Lsr/Roxr/Ror opcode\r
324 static int EmitAsr(int op,int type,int dir,int count,int size,int usereg)\r
325 {\r
326   char pct[8]="";\r
327   int shift=32-(8<<size);\r
328 \r
329   if (count>=1) sprintf(pct,"#%d",count); // Fixed count\r
330 \r
331   if (count<0)\r
332   {\r
333     ot("  mov r2,r8,lsr #9 ;@ Get 'n'\n");\r
334     ot("  and r2,r2,#7\n\n"); strcpy(pct,"r2");\r
335   }\r
336 \r
337   if (usereg)\r
338   {\r
339     ot(";@ Use Dn for count:\n");\r
340     ot("  ldr r2,[r7,r2,lsl #2]\n");\r
341     ot("  and r2,r2,#63\n");\r
342     ot("\n");\r
343   }\r
344 \r
345   // Take 2*n cycles:\r
346   if (count<0) ot("  sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n");\r
347   else Cycles+=count<<1;\r
348 \r
349   if (type<2)\r
350   {\r
351     // Asr/Lsr\r
352     if (dir==0 && size<2)\r
353     {\r
354       ot(";@ For shift right, also copy to lowest bits (to get carry bit):\n");\r
355       ot("  orr r0,r0,r0,lsr #%d\n",32-(8<<size));\r
356       ot("\n");\r
357     }\r
358 \r
359     ot(";@ Shift register:\n");\r
360     if (type==0) ot("  movs r0,r0,%s %s\n",dir?"asl":"asr",pct);\r
361     if (type==1) ot("  movs r0,r0,%s %s\n",dir?"lsl":"lsr",pct);\r
362     OpGetFlags(0,1);\r
363     ot("\n");\r
364 \r
365     if (size<2)\r
366     {\r
367       ot(";@ Check if result is zero:\n");\r
368       ot("  movs r2,r0,lsr #%d\n",shift);\r
369       ot("  orreq r9,r9,#0x40000000\n");\r
370       ot("\n");\r
371     }\r
372   }\r
373 \r
374   // --------------------------------------\r
375   if (type==2)\r
376   {\r
377     // Roxr\r
378     int wide=8<<size;\r
379 \r
380     if (shift) ot("  mov r0,r0,lsr #%d ;@ Shift down\n",shift);\r
381 \r
382     ot(";@ Rotate register through X:\n");\r
383     if (strcmp("r2",pct)!=0) { ot("  mov r2,%s\n",pct); strcpy(pct,"r2"); } // Get into register\r
384 \r
385     if (count!=8)\r
386     {\r
387       ot(";@ Reduce r2 until <0:\n");\r
388       ot("Reduce_%.4x%s\n",op,ms?"":":");\r
389       ot("  subs r2,r2,#%d\n",wide+1);\r
390       ot("  bpl Reduce_%.4x\n",op);\r
391       ot("  add r2,r2,#%d ;@ Now r2=0-%d\n",wide+1,wide);\r
392       ot("\n");\r
393     }\r
394 \r
395     if (dir) ot("  rsb r2,r2,#%d ;@ Reverse direction\n",wide+1);\r
396 \r
397     ot(";@ Rotate bits:\n");\r
398     ot("  mov r3,r0,lsr r2 ;@ Get right part\n");\r
399     ot("  rsb r2,r2,#%d\n",wide+1);\r
400     ot("  movs r0,r0,lsl r2 ;@ Get left part\n");\r
401     ot("  orr r0,r3,r0 ;@ r0=Rotated value\n");\r
402 \r
403     ot(";@ Insert X bit into r2-1:\n");\r
404     ot("  ldrb r3,[r7,#0x45]\n");\r
405     ot("  sub r2,r2,#1\n");\r
406     ot("  and r3,r3,#2\n");\r
407     ot("  mov r3,r3,lsr #1\n");\r
408     ot("  orr r0,r0,r3,lsl r2\n");\r
409     ot("\n");\r
410 \r
411     if (shift) ot("  movs r0,r0,lsl #%d ;@ Shift up and get correct NC flags\n",shift);\r
412     OpGetFlags(0,1);\r
413     ot("\n");\r
414   }\r
415 \r
416   // --------------------------------------\r
417   if (type==3)\r
418   {\r
419     // Ror\r
420     if (size<2)\r
421     {\r
422       ot(";@ Mirror value in whole 32 bits:\n");\r
423       if (size<=0) ot("  orr r0,r0,r0,lsr #8\n");\r
424       if (size<=1) ot("  orr r0,r0,r0,lsr #16\n");\r
425       ot("\n");\r
426     }\r
427 \r
428     ot(";@ Rotate register:\n");\r
429     if (count<0)\r
430     {\r
431       if (dir) ot("  rsb r2,%s,#32\n",pct);\r
432       ot("  movs r0,r0,ror %s\n",pct);\r
433     }\r
434     else\r
435     {\r
436       int ror=count;\r
437       if (dir) ror=32-ror;\r
438       if (ror&31) ot("  movs r0,r0,ror #%d\n",ror);\r
439     }\r
440 \r
441     if (dir)\r
442     {\r
443       ot(";@ Get carry bit from bit 0:\n");\r
444       ot("  mov r9,#0\n");\r
445       ot("  ands r2,r0,#1\n");\r
446       ot("  orrne r9,r9,#0x20000000\n");\r
447     }\r
448     else\r
449     {\r
450       OpGetFlags(0,0);\r
451     }\r
452     ot("\n");\r
453 \r
454   }\r
455   // --------------------------------------\r
456   \r
457   return 0;\r
458 }\r
459 \r
460 // Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn\r
461 // (ccc=count, d=direction xx=size extension, u=use reg for count, tt=type, nnn=register Dn)\r
462 int OpAsr(int op)\r
463 {\r
464   int ea=0,use=0;\r
465   int count=0,dir=0;\r
466   int size=0,usereg=0,type=0;\r
467 \r
468   ea=0;\r
469   count =(op>>9)&7;\r
470   dir   =(op>>8)&1;\r
471   size  =(op>>6)&3;\r
472   if (size>=3) return 1; // todo Asr EA\r
473   usereg=(op>>5)&1;\r
474   type  =(op>>3)&3;\r
475 \r
476   if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8\r
477 \r
478   // Use the same opcode for target registers:\r
479   use=op&~0x0007;\r
480 \r
481   // As long as count is not 8, use the same opcode for all shift counts::\r
482   if (usereg==0 && count!=8) { use|=0x0e00; count=-1; }\r
483   if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn\r
484 \r
485   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
486 \r
487   OpStart(op); Cycles=size<2?6:8;\r
488 \r
489   EaCalc(10,0x0007, ea,size);\r
490   EaRead(10,     0, ea,size,1);\r
491 \r
492   EmitAsr(op,type,dir,count, size,usereg);\r
493 \r
494   EaWrite(10,    0, ea,size,1);\r
495 \r
496   OpEnd();\r
497 \r
498   return 0;\r
499 }\r
500 \r
501 // Asr/l/Ror/l etc EA - 11100ttd 11eeeeee \r
502 int OpAsrEa(int op)\r
503 {\r
504   int use=0,type=0,dir=0,ea=0,size=1;\r
505 \r
506   type=(op>>9)&3;\r
507   dir =(op>>8)&1;\r
508   ea  = op&0x3f;\r
509 \r
510   if (ea<0x10) return 1;\r
511   // See if we can do this opcode:\r
512   if (EaCanRead(ea,0)==0) return 1;\r
513   if (EaCanWrite(ea)==0) return 1;\r
514 \r
515   use=OpBase(op);\r
516   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
517 \r
518   OpStart(op); Cycles=8;\r
519 \r
520   EaCalc (10,0x003f,ea,size);\r
521   EaRead (10,     0,ea,size,1);\r
522 \r
523   EmitAsr(op,type,dir,1, size,0);\r
524 \r
525   ot(";@ Save shifted value back to EA:\n");\r
526   ot("  mov r1,r0\n");\r
527   EaWrite(10,     1,ea,size,1);\r
528 \r
529   OpEnd();\r
530   return 0;\r
531 }\r