license info at top of Cyclone source files
[cyclone68000.git] / Cyclone / OpLogic.cpp
CommitLineData
619b1824 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
6003a768 9#include "app.h"\r
10\r
11// --------------------- Opcodes 0x0100+ ---------------------\r
12// Emit a Btst (Register) opcode 0000nnn1 00aaaaaa\r
13int 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
71int 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
126int 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
189int 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
216int 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
245int 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
277int 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
324static 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
462int 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
502int 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