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