license info at top of Cyclone source files
[cyclone68000.git] / Cyclone / OpArith.cpp
CommitLineData
6003a768 1\r
619b1824 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 0x0000+ ---------------------\r
12// Emit an Ori/And/Sub/Add/Eor/Cmp Immediate opcode, 0000ttt0 00aaaaaa\r
13int OpArith(int op)\r
14{\r
15 int type=0,size=0;\r
16 int sea=0,tea=0;\r
17 int use=0;\r
18\r
19 // Get source and target EA\r
20 type=(op>>9)&7; if (type==4 || type>=7) return 1;\r
21 size=(op>>6)&3; if (size>=3) return 1;\r
22 sea= 0x003c;\r
23 tea=op&0x003f;\r
24\r
25 // See if we can do this opcode:\r
26 if (EaCanRead(tea,size)==0) return 1;\r
27 if (type!=6 && EaCanWrite(tea)==0) return 1;\r
28\r
29 use=OpBase(op);\r
30 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
31\r
32 OpStart(op); Cycles=4;\r
33\r
34 EaCalc(10,0x0000, sea,size);\r
35 EaRead(10, 10, sea,size,1);\r
36\r
37 EaCalc(11,0x003f, tea,size);\r
38 EaRead(11, 0, tea,size,1);\r
39\r
40 ot(";@ Do arithmetic:\n");\r
41\r
42 if (type==0) ot(" orr r1,r0,r10\n");\r
43 if (type==1) ot(" and r1,r0,r10\n");\r
44 if (type==2) ot(" subs r1,r0,r10 ;@ Defines NZCV\n");\r
45 if (type==3) ot(" adds r1,r0,r10 ;@ Defines NZCV\n");\r
46 if (type==5) ot(" eor r1,r0,r10\n");\r
47 if (type==6) ot(" cmp r0,r10 ;@ Defines NZCV\n");\r
48\r
49 if (type<2 || type==5) ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); // 0,1,5\r
50\r
51 if (type< 2) OpGetFlags(0,0); // Ori/And\r
52 if (type==2) OpGetFlags(1,1); // Sub: Subtract/X-bit\r
53 if (type==3) OpGetFlags(0,1); // Add: X-bit\r
54 if (type==5) OpGetFlags(0,0); // Eor\r
55 if (type==6) OpGetFlags(1,0); // Cmp: Subtract\r
56 ot("\n");\r
57\r
58 if (type!=6)\r
59 {\r
60 EaWrite(11, 1, tea,size,1);\r
61 }\r
62\r
63 // Correct cycles:\r
64 if (type==6)\r
65 {\r
66 if (size>=2 && tea<0x10) Cycles+=2;\r
67 }\r
68 else\r
69 {\r
70 if (size>=2) Cycles+=4;\r
71 if (tea>=0x10) Cycles+=4;\r
72 if (Amatch && type==1 && size>=2 && tea<0x10) Cycles-=2;\r
73 }\r
74\r
75 OpEnd();\r
76\r
77 return 0;\r
78}\r
79\r
80// --------------------- Opcodes 0x5000+ ---------------------\r
81int OpAddq(int op)\r
82{\r
83 // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA)\r
84 int num=0,type=0,size=0,ea=0;\r
85 int use=0;\r
86 char count[16]="";\r
87 int shift=0;\r
88\r
89 num =(op>>9)&7; if (num==0) num=8;\r
90 type=(op>>8)&1;\r
91 size=(op>>6)&3; if (size>=3) return 1;\r
92 ea = op&0x3f;\r
93\r
94 // See if we can do this opcode:\r
95 if (EaCanRead (ea,size)==0) return 1;\r
96 if (EaCanWrite(ea )==0) return 1;\r
97\r
98 use=op; if (ea<0x38) use&=~7;\r
99 if ((ea&0x38)==0x08) { size=2; use&=~0xc0; } // Every addq #n,An is 32-bit\r
100\r
101 if (num!=8) use|=0x0e00; // If num is not 8, use same handler\r
102 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
103\r
104 OpStart(op);\r
105 Cycles=ea<8?4:8;\r
106 if (size>=2 && ea!=8) Cycles+=4;\r
107\r
108 EaCalc(10,0x003f, ea,size);\r
109 EaRead(10, 0, ea,size,1);\r
110\r
111 shift=32-(8<<size);\r
112\r
113 if (num!=8)\r
114 {\r
115 int lsr=9-shift;\r
116\r
117 if (lsr>=0) ot(" mov r2,r8,lsr #%d ;@ Get quick value\n", lsr);\r
118 else ot(" mov r2,r8,lsl #%d ;@ Get quick value\n",-lsr);\r
119\r
120 ot(" and r2,r2,#0x%.4x\n",7<<shift);\r
121 ot("\n");\r
122 strcpy(count,"r2");\r
123 }\r
124\r
125 if (num==8) sprintf(count,"#0x%.4x",8<<shift);\r
126\r
127 if (type==0) ot(" adds r1,r0,%s\n",count);\r
128 if (type==1) ot(" subs r1,r0,%s\n",count);\r
129\r
130 if ((ea&0x38)!=0x08) OpGetFlags(type,1);\r
131 ot("\n");\r
132\r
133 EaWrite(10, 1, ea,size,1);\r
134\r
135 OpEnd();\r
136\r
137 return 0;\r
138}\r
139\r
140// --------------------- Opcodes 0x8000+ ---------------------\r
141// 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA)\r
142int OpArithReg(int op)\r
143{\r
144 int use=0;\r
145 int type=0,size=0,dir=0,rea=0,ea=0;\r
146\r
147 type=(op>>12)&5;\r
148 rea =(op>> 9)&7;\r
149 dir =(op>> 8)&1;\r
150 size=(op>> 6)&3; if (size>=3) return 1;\r
151 ea = op&0x3f;\r
152\r
153 if (dir && ea<0x10) return 1; // addx/subx opcode\r
154\r
155 // See if we can do this opcode:\r
156 if (dir==0 && EaCanWrite(rea)==0) return 1;\r
157 if (dir && EaCanWrite( ea)==0) return 1;\r
158\r
159 use=OpBase(op);\r
160 use&=~0x0e00; // Use same opcode for Dn\r
161 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
162\r
163 OpStart(op); Cycles=4;\r
164\r
165 ot(";@ Get r10=EA r11=EA value\n");\r
166 EaCalc(10,0x003f, ea,size);\r
167 EaRead(10, 11, ea,size,1);\r
168 ot(";@ Get r0=Register r1=Register value\n");\r
169 EaCalc( 0,0x0e00,rea,size);\r
170 EaRead( 0, 1,rea,size,1);\r
171\r
172 ot(";@ Do arithmetic:\n");\r
173 if (type==0) ot(" orr ");\r
174 if (type==1) ot(" subs ");\r
175 if (type==4) ot(" and ");\r
176 if (type==5) ot(" adds ");\r
177 if (dir) ot("r1,r11,r1\n");\r
178 else ot("r1,r1,r11\n");\r
179\r
180 if ((type&1)==0) ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
181\r
182 OpGetFlags(type==1,type&1); // 1==subtract\r
183 ot("\n");\r
184\r
185 ot(";@ Save result:\n");\r
186 if (dir) EaWrite(10, 1, ea,size,1);\r
187 else EaWrite( 0, 1,rea,size,1);\r
188\r
189 if (size==1 && ea>=0x10) Cycles+=4;\r
190 if (size>=2) { if (ea<0x10) Cycles+=4; else Cycles+=2; }\r
191\r
192 OpEnd();\r
193\r
194 return 0;\r
195}\r
196\r
197// --------------------- Opcodes 0x80c0+ ---------------------\r
198int OpMul(int op)\r
199{\r
200 // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA)\r
201 int type=0,rea=0,sign=0,ea=0;\r
202 int use=0;\r
203\r
204 type=(op>>14)&1; // div/mul\r
205 rea =(op>> 9)&7;\r
206 sign=(op>> 8)&1;\r
207 ea = op&0x3f;\r
208\r
209 // See if we can do this opcode:\r
210 if (EaCanRead(ea,1)==0) return 1;\r
211\r
212 use=OpBase(op);\r
213 use&=~0x0e00; // Use same for all registers\r
214 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
215\r
216 OpStart(op); Cycles=type?70:133;\r
217\r
218 EaCalc(10,0x003f, ea, 1);\r
219 EaRead(10, 10, ea, 1);\r
220\r
221 EaCalc (0,0x0e00,rea, 2);\r
222 EaRead (0, 2,rea, 2);\r
223\r
224 if (type==0)\r
225 {\r
226 ot(" cmp r10,#0\n");\r
227 ot(" moveq r10,#1 ;@ Divide by zero\n");\r
228 ot("\n");\r
229 \r
230 if (sign)\r
231 {\r
232 ot(" mov r11,#0 ;@ r11 = 1 if the result is negative\n");\r
233 ot(" eorlt r11,r11,#1\n");\r
234 ot(" rsblt r10,r10,#0 ;@ Make r10 positive\n");\r
235 ot("\n");\r
236 ot(" cmp r2,#0\n");\r
237 ot(" eorlt r11,r11,#1\n");\r
238 ot(" rsblt r2,r2,#0 ;@ Make r2 positive\n");\r
239 ot("\n");\r
240 }\r
241\r
242 ot(";@ Divide r2 by r10\n");\r
243 ot(" mov r3,#0\n");\r
244 ot(" mov r1,r10\n");\r
245 ot("\n");\r
246 ot(";@ Shift up divisor till it's just less than numerator\n");\r
247 ot("Shift%.4x%s\n",op,ms?"":":");\r
248 ot(" cmp r1,r2,lsr #1\n");\r
249 ot(" movls r1,r1,lsl #1\n");\r
250 ot(" bcc Shift%.4x\n",op);\r
251 ot("\n");\r
252\r
253 ot("Divide%.4x%s\n",op,ms?"":":");\r
254 ot(" cmp r2,r1\n");\r
255 ot(" adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n");\r
256 ot(" subcs r2,r2,r1\n");\r
257 ot(" teq r1,r10\n");\r
258 ot(" movne r1,r1,lsr #1\n");\r
259 ot(" bne Divide%.4x\n",op);\r
260 ot("\n");\r
261\r
262 if (sign)\r
263 {\r
264 ot(" tst r11,r11\n");\r
265 ot(" rsbne r3,r3,#0 ;@ Negate if result is negative\n");\r
266 }\r
267\r
268 ot(" mov r11,r2 ;@ Remainder\n");\r
269\r
270 ot(" adds r1,r3,#0 ;@ Defines NZ, clears CV\n");\r
271 OpGetFlags(0,0);\r
272\r
273 ot(" mov r1,r1,lsl #16 ;@ Clip to 16-bits\n");\r
274 ot(" mov r1,r1,lsr #16\n");\r
275 ot(" orr r1,r1,r11,lsl #16 ;@ Insert remainder\n");\r
276 }\r
277\r
278 if (type==1)\r
279 {\r
280 char *shift="asr";\r
281\r
282 ot(";@ Get 16-bit signs right:\n");\r
283 if (sign==0) { ot(" mov r10,r10,lsl #16\n"); shift="lsr"; }\r
284 ot(" mov r2,r2,lsl #16\n");\r
285\r
286 if (sign==0) ot(" mov r10,r10,lsr #16\n");\r
287 ot(" mov r2,r2,%s #16\n",shift);\r
288 ot("\n");\r
289\r
290 ot(" mul r1,r2,r10\n");\r
291 ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
292 OpGetFlags(0,0);\r
293\r
294 if (Amatch && ea==0x3c) Cycles-=4;\r
295 }\r
296 ot("\n");\r
297\r
298 EaWrite(0, 1,rea, 2);\r
299\r
300\r
301 OpEnd();\r
302\r
303 return 0;\r
304}\r
305\r
306// Get X Bit into carry - trashes r2\r
307static int GetXBit(int subtract)\r
308{\r
309 ot(";@ Get X bit:\n");\r
310 ot(" ldrb r2,[r7,#0x45]\n");\r
311 if (subtract) ot(" mvn r2,r2,lsl #28 ;@ Invert it\n");\r
312 else ot(" mov r2,r2,lsl #28\n");\r
313 ot(" msr cpsr_flg,r2 ;@ Get into Carry\n");\r
314 ot("\n");\r
315 return 0;\r
316}\r
317\r
318// --------------------- Opcodes 0x8100+ ---------------------\r
319// 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad)\r
320int OpAbcd(int op)\r
321{\r
322 int use=0;\r
323 int type=0,sea=0,addr=0,dea=0;\r
324 \r
325 type=(op>>14)&1;\r
326 dea =(op>> 9)&7;\r
327 addr=(op>> 3)&1;\r
328 sea = op &7;\r
329\r
330 if (addr) { sea|=0x20; dea|=0x20; }\r
331\r
332 use=op&~0x0e07; // Use same opcode for all registers\r
333 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
334\r
335 OpStart(op); Cycles=6;\r
336\r
337 EaCalc( 0,0x0007, sea,0);\r
338 EaRead( 0, 10, sea,0,1);\r
339 EaCalc(11,0x0e00, dea,0);\r
340 EaRead(11, 1, dea,0,1);\r
341\r
342 ot(" ldrb r2,[r7,#0x45] ;@ Get X bit\n");\r
343 ot(" tst r2,#2\n");\r
344 ot(" addne r10,r10,#0x01000000 ;@ Add carry bit\n");\r
345\r
346 if (type)\r
347 {\r
348 ot(";@ Add units into r2:\n");\r
349 ot(" and r2,r1, #0x0f000000\n");\r
350 ot(" and r0,r10,#0x0f000000\n");\r
351 ot(" add r2,r2,r0\n");\r
352 ot(" cmp r2,#0x0a000000\n");\r
353 ot(" addpl r1,r1,#0x06000000 ;@ Decimal adjust units\n");\r
354 ot(" add r1,r1,r10 ;@ Add BCD\n");\r
355 ot(" mov r0,r1,lsr #24\n");\r
356 ot(" cmp r0,#0xa0\n");\r
357 ot(" addpl r1,r1,#0x60000000 ;@ Decimal adjust tens\n");\r
358 OpGetFlags(0,1);\r
359 }\r
360 else\r
361 {\r
362 ot(";@ Sub units into r2:\n");\r
363 ot(" and r2,r1, #0x0f000000\n");\r
364 ot(" and r0,r10,#0x0f000000\n");\r
365 ot(" subs r2,r2,r0\n");\r
366 ot(" submi r1,r1,#0x06000000 ;@ Decimal adjust units\n");\r
367 ot(" subs r1,r1,r10 ;@ Subtract BCD\n");\r
368 ot(" submis r1,r1,#0x60000000 ;@ Decimal adjust tens\n");\r
369 OpGetFlags(1,1);\r
370 }\r
371 ot("\n");\r
372\r
373 EaWrite(11, 1, dea,0,1);\r
374\r
375 OpEnd();\r
376\r
377 return 0;\r
378}\r
379\r
380// --------------------- Opcodes 0x90c0+ ---------------------\r
381// Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA)\r
382int OpAritha(int op)\r
383{\r
384 int use=0;\r
385 int type=0,size=0,sea=0,dea=0;\r
386\r
387 // Suba/Cmpa/Adda/(invalid):\r
388 type=(op>>13)&3; if (type>=3) return 1;\r
389\r
390 size=(op>>8)&1; size++;\r
391 dea=(op>>9)&7; dea|=8; // Dest=An\r
392 sea=op&0x003f; // Source\r
393\r
394 // See if we can do this opcode:\r
395 if (EaCanRead(sea,size)==0) return 1;\r
396\r
397 use=OpBase(op);\r
398 use&=~0x0e00; // Use same opcode for An\r
399 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
400\r
401 OpStart(op); Cycles=4;\r
402 EaCalc ( 0,0x003f, sea,size);\r
403 EaRead ( 0, 10, sea,size);\r
404\r
405 EaCalc ( 0,0x0e00, dea,2);\r
406 EaRead ( 0, 1, dea,2);\r
407\r
408 if (type==0) ot(" sub r1,r1,r10\n");\r
409 if (type==1) ot(" cmp r1,r10 ;@ Defines NZCV\n");\r
410 if (type==1) OpGetFlags(1,0); // Get Cmp flags\r
411 if (type==2) ot(" add r1,r1,r10\n");\r
412 ot("\n");\r
413 \r
414 EaWrite( 0, 1, dea,2);\r
415\r
416 if (Amatch && sea==0x3c) Cycles-=size<2?4:8; // Correct?\r
417 if (size>=2) { if (sea<0x10) Cycles+=4; else Cycles+=2; }\r
418\r
419 OpEnd();\r
420\r
421 return 0;\r
422}\r
423\r
424// --------------------- Opcodes 0x9100+ ---------------------\r
425// Emit a Subx/Addx opcode, 1t01ddd1 zz000sss addx.z Ds,Dd\r
426int OpAddx(int op)\r
427{\r
428 int use=0;\r
429 int type=0,size=0,dea=0,sea=0;\r
430\r
431 type=(op>>12)&5;\r
432 dea =(op>> 9)&7;\r
433 size=(op>> 6)&3; if (size>=3) return 1;\r
434 sea = op&0x3f;\r
435\r
436 // See if we can do this opcode:\r
437 if (EaCanRead(sea,size)==0) return 1;\r
438 if (EaCanWrite(dea)==0) return 1;\r
439\r
440 use=OpBase(op);\r
441 use&=~0x0e00; // Use same opcode for Dn\r
442 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
443\r
444 OpStart(op); Cycles=8;\r
445\r
446 ot(";@ Get r10=EA r11=EA value\n");\r
447 EaCalc( 0,0x003f,sea,size);\r
448 EaRead( 0, 11,sea,size,1);\r
449 ot(";@ Get r0=Register r1=Register value\n");\r
450 EaCalc( 0,0x0e00,dea,size);\r
451 EaRead( 0, 1,dea,size,1);\r
452\r
453 ot(";@ Do arithmetic:\n");\r
454 GetXBit(type==1);\r
455\r
456 if (type==5 && size<2)\r
457 {\r
458 ot(";@ Make sure the carry bit will tip the balance:\n");\r
459 if (size==0) ot(" ldr r2,=0x00ffffff\n");\r
460 else ot(" ldr r2,=0x0000ffff\n");\r
461 ot(" orr r11,r11,r2\n");\r
462 ot("\n");\r
463 }\r
464\r
465 if (type==1) ot(" sbcs r1,r1,r11\n");\r
466 if (type==5) ot(" adcs r1,r1,r11\n");\r
467 OpGetFlags(type==1,1); // subtract\r
468 ot("\n");\r
469\r
470 ot(";@ Save result:\n");\r
471 EaWrite( 0, 1, dea,size,1);\r
472\r
473 OpEnd();\r
474\r
475 return 0;\r
476}\r
477\r
478// --------------------- Opcodes 0xb000+ ---------------------\r
479// Emit a Cmp/Eor opcode, 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea)\r
480int OpCmpEor(int op)\r
481{\r
482 int rea=0,eor=0;\r
483 int size=0,ea=0,use=0;\r
484\r
485 // Get EA and register EA\r
486 rea=(op>>9)&7;\r
487 eor=(op>>8)&1;\r
488 size=(op>>6)&3; if (size>=3) return 1;\r
489 ea=op&0x3f;\r
490\r
491 // See if we can do this opcode:\r
492 if (EaCanRead(ea,size)==0) return 1;\r
493 if (eor && EaCanWrite(ea)==0) return 1;\r
494\r
495 use=OpBase(op);\r
496 use&=~0x0e00; // Use 1 handler for register d0-7\r
497 if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
498\r
499 OpStart(op); Cycles=eor?8:4;\r
500\r
501 ot(";@ Get EA into r10 and value into r0:\n");\r
502 EaCalc (10,0x003f, ea,size);\r
503 EaRead (10, 0, ea,size,1);\r
504\r
505 ot(";@ Get register operand into r1:\n");\r
506 EaCalc (1 ,0x0e00, rea,size);\r
507 EaRead (1, 1, rea,size,1);\r
508\r
509 ot(";@ Do arithmetic:\n");\r
510 if (eor==0) ot(" cmp r1,r0\n");\r
511 if (eor)\r
512 {\r
513 ot(" eor r1,r0,r1\n");\r
514 ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
515 }\r
516\r
517 OpGetFlags(eor==0,0); // Cmp like subtract\r
518 ot("\n");\r
519\r
520 if (size>=2) Cycles+=4; // Correct?\r
521 if (ea==0x3c) Cycles-=4;\r
522\r
523 if (eor) EaWrite(10, 1,ea,size,1);\r
524\r
525 OpEnd();\r
526 return 0;\r
527}\r
528\r