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