added copyright line to top of source files next to license information
[cyclone68000.git] / Cyclone / OpLogic.cpp
CommitLineData
619b1824 1\r
2// This file is part of the Cyclone 68000 Emulator\r
3\r
c41b9b97 4// Copyright (c) 2011 FinalDave (emudave (at) gmail.com)\r
5\r
619b1824 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
6003a768 11#include "app.h"\r
12\r
13// --------------------- Opcodes 0x0100+ ---------------------\r
14// Emit a Btst (Register) opcode 0000nnn1 00aaaaaa\r
15int 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
73int 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
128int 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
191int 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
218int 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
247int 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
279int 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
326static 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
464int 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
504int 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