f762ea1f57bebcd60203445908003b3bee158a96
[cyclone68000.git] / Cyclone / OpMove.cpp
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
9 #include "app.h"\r
10 \r
11 // --------------------- Opcodes 0x1000+ ---------------------\r
12 // Emit a Move opcode, 00xxdddd ddssssss\r
13 int OpMove(int op)\r
14 {\r
15   int sea=0,tea=0;\r
16   int size=0,use=0;\r
17   int movea=0;\r
18 \r
19   // Get source and target EA\r
20   sea = op&0x003f;\r
21   tea =(op&0x01c0)>>3;\r
22   tea|=(op&0x0e00)>>9;\r
23 \r
24   if (tea>=8 && tea<0x10) movea=1;\r
25 \r
26   // Find size extension\r
27   switch (op&0x3000)\r
28   {\r
29     default: return 1;\r
30     case 0x1000: size=0; break;\r
31     case 0x3000: size=1; break;\r
32     case 0x2000: size=2; break;\r
33   }\r
34 \r
35   if (movea && size<1) return 1; // movea.b is invalid\r
36 \r
37   // See if we can do this opcode:\r
38   if (EaCanRead (sea,size)==0) return 1;\r
39   if (EaCanWrite(tea     )==0) return 1;\r
40 \r
41   use=OpBase(op);\r
42   if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7\r
43   \r
44   if (tea>=0x18 && tea<0x28 && (tea&7)==7) use|=0x0e00; // Specific handler for (a7)+ and -(a7)\r
45 \r
46   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
47 \r
48   OpStart(op); Cycles=4;\r
49 \r
50   EaCalc(0,0x003f,sea,size);\r
51   EaRead(0,     0,sea,size);\r
52 \r
53   ot("  adds r1,r0,#0 ;@ Defines NZ, clears CV\n");\r
54 \r
55   if (movea==0)  ot("  mrs r9,cpsr ;@ r9=NZCV flags\n");\r
56   ot("\n");\r
57 \r
58   if (movea) size=2; // movea always expands to 32-bits\r
59 \r
60   EaCalc (0,0x0e00,tea,size);\r
61   EaWrite(0,     1,tea,size);\r
62 \r
63   OpEnd();\r
64   return 0;\r
65 }\r
66 \r
67 // --------------------- Opcodes 0x41c0+ ---------------------\r
68 // Emit an Lea opcode, 0100nnn1 11aaaaaa\r
69 int OpLea(int op)\r
70 {\r
71   int use=0;\r
72   int sea=0,tea=0;\r
73 \r
74   sea= op&0x003f;\r
75   tea=(op&0x0e00)>>9; tea|=8;\r
76 \r
77   if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode:\r
78 \r
79   use=OpBase(op);\r
80   use&=~0x0e00; // Also use 1 handler for target ?0-7\r
81   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
82 \r
83   OpStart(op); Cycles=4;\r
84 \r
85   EaCalc (1,0x003f,sea,0); // Lea\r
86   EaCalc (0,0x0e00,tea,2);\r
87   EaWrite(0,     1,tea,2);\r
88 \r
89   if (Amatch)\r
90   {\r
91     // Correct?\r
92          if (sea< 0x18) Cycles+=4;\r
93     else if (sea==0x30) Cycles+=12;\r
94     else Cycles+=8;\r
95   }\r
96 \r
97   OpEnd();\r
98 \r
99   return 0;\r
100 }\r
101 \r
102 // --------------------- Opcodes 0x40c0+ ---------------------\r
103 \r
104 // Pack our flags into r1, in SR/CCR register format\r
105 // trashes r0,r2\r
106 void OpFlagsToReg(int high)\r
107 {\r
108   ot("  mov r1,r9,lsr #28   ;@ ____NZCV\n");\r
109   ot("  eor r0,r1,r1,ror #1 ;@ Bit 0=C^V\n");\r
110   ot("  tst r0,#1           ;@ 1 if C!=V\n");\r
111   ot("  eorne r1,r1,#3      ;@ ____NZVC\n");\r
112   ot("\n");\r
113   ot("  ldrb r0,[r7,#0x45]  ;@ X bit\n");\r
114   if (high) ot("  ldrb r2,[r7,#0x44]  ;@ Include SR high\n");\r
115   ot("  and r0,r0,#0x02\n");\r
116   if (high) ot("  orr r1,r1,r2,lsl #8\n");\r
117   ot("  orr r1,r1,r0,lsl #3 ;@ ___XNZVC\n");\r
118   ot("\n");\r
119 }\r
120 \r
121 // Convert SR/CRR register in r0 to our flags\r
122 // trashes r0,r1\r
123 void OpRegToFlags(int high)\r
124 {\r
125   ot("  eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");\r
126   ot("  mov r2,r0,lsr #3    ;@ r2=___XN\n");\r
127   ot("  tst r1,#1           ;@ 1 if C!=V\n");\r
128   ot("  eorne r0,r0,#3      ;@ ___XNZCV\n");\r
129   ot("  strb r2,[r7,#0x45]  ;@ Store X bit\n");\r
130   ot("  mov r9,r0,lsl #28   ;@ r9=NZCV...\n");\r
131 \r
132   if (high)\r
133   {\r
134     ot("  mov r0,r0,ror #8\n");\r
135     ot("  strb r0,[r7,#0x44] ;@ Store SR high\n");\r
136   }\r
137   ot("\n");\r
138 }\r
139 \r
140 static void SuperCheck(int op)\r
141 {\r
142   ot("  ldrb r0,[r7,#0x44] ;@ Get SR high\n");\r
143   ot("  tst r0,#0x20 ;@ Check we are in supervisor mode\n");\r
144   ot("  beq WrongMode%.4x ;@ No\n",op);\r
145   ot("\n");\r
146 }\r
147 \r
148 static void SuperEnd(int op)\r
149 {\r
150   ot("WrongMode%.4x%s\n",op,ms?"":":");\r
151   ot(";@ todo - cause an exception\n");\r
152   OpEnd();\r
153 }\r
154 \r
155 // Move SR opcode, 01000tt0 11aaaaaa move to SR\r
156 int OpMoveSr(int op)\r
157 {\r
158   int type=0,ea=0;\r
159   int use=0,size=1;\r
160 \r
161   type=(op>>9)&3;\r
162   ea=op&0x3f;\r
163 \r
164   switch(type)\r
165   {\r
166     case 0: case 1:\r
167       if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode:\r
168     break;\r
169 \r
170     default: return 1; // todo\r
171 \r
172     case 2: case 3:\r
173       if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode:\r
174     break;\r
175   }\r
176 \r
177   use=OpBase(op);\r
178   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
179 \r
180   OpStart(op);\r
181        if (type==0) Cycles=8;\r
182   else if (type==1) Cycles=6;\r
183   else Cycles=12;\r
184 \r
185   if (Amatch && ea==0x3c) Cycles-=4; // Correct?\r
186 \r
187   if (type==0 || type==3) SuperCheck(op);\r
188 \r
189   if (type==0 || type==1)\r
190   {\r
191     OpFlagsToReg(type==0);\r
192     EaCalc (0,0x003f,ea,size);\r
193     EaWrite(0,     1,ea,size);\r
194   }\r
195 \r
196   if (type==2 || type==3)\r
197   {\r
198     EaCalc(0,0x003f,ea,size);\r
199     EaRead(0,     0,ea,size);\r
200     OpRegToFlags(type==3);\r
201     if (type==3) CheckInterrupt();\r
202   }\r
203 \r
204   OpEnd();\r
205 \r
206   if (type==0 || type==3) SuperEnd(op);\r
207 \r
208   return 0;\r
209 }\r
210 \r
211 \r
212 // Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100\r
213 int OpArithSr(int op)\r
214 {\r
215   int type=0,ea=0;\r
216   int use=0,size=0;\r
217 \r
218   type=(op>>9)&5; if (type==4) return 1;\r
219   size=(op>>6)&1;\r
220   ea=0x3c;\r
221 \r
222   use=OpBase(op);\r
223   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
224 \r
225   OpStart(op); Cycles=16;\r
226 \r
227   SuperCheck(op);\r
228 \r
229   EaCalc(0,0x003f,ea,size);\r
230   EaRead(0,    10,ea,size);\r
231 \r
232   OpFlagsToReg(size);\r
233   if (type==0) ot("  orr r0,r1,r10\n");\r
234   if (type==1) ot("  and r0,r1,r10\n");\r
235   if (type==5) ot("  eor r0,r1,r10\n");\r
236   OpRegToFlags(size);\r
237   if (size) CheckInterrupt();\r
238 \r
239   OpEnd();\r
240   SuperEnd(op);\r
241 \r
242   return 0;\r
243 }\r
244 \r
245 // --------------------- Opcodes 0x4850+ ---------------------\r
246 // Emit an Pea opcode, 01001000 01aaaaaa\r
247 int OpPea(int op)\r
248 {\r
249   int use=0;\r
250   int ea=0;\r
251 \r
252   ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode\r
253   if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode:\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=20;\r
259 \r
260   EaCalc (1,0x003f, ea,0);\r
261   ot("\n");\r
262   ot("  ldr r0,[r7,#0x3c]\n");\r
263   ot("  sub r0,r0,#4 ;@ Predecrement A7\n");\r
264   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");\r
265   ot("\n");\r
266   MemHandler(1,2); // Write 32-bit\r
267   ot("\n");\r
268 \r
269   OpEnd();\r
270 \r
271   return 0;\r
272 }\r
273 \r
274 // --------------------- Opcodes 0x4880+ ---------------------\r
275 // Emit a Movem opcode, 01001d00 1xeeeeee regmask\r
276 int OpMovem(int op)\r
277 {\r
278   int size=0,ea=0,cea=0,dir=0;\r
279   int use=0,decr=0,change=0;\r
280 \r
281   size=((op>>6)&1)+1;\r
282   ea=op&0x003f;\r
283   dir=(op>>10)&1; // Direction\r
284 \r
285   if (ea<0x10 || ea>0x39) return 1; // Invalid EA\r
286   if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1;\r
287   if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr\r
288 \r
289   // See if we can do this opcode:\r
290   if (EaCanWrite(ea)==0) return 1;\r
291 \r
292   cea=ea; if (change) cea=0x10;\r
293 \r
294   use=OpBase(op);\r
295   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
296 \r
297   OpStart(op);\r
298 \r
299   ot("  stmdb sp!,{r9} ;@ Push r9\n");\r
300   ot("  ldrh r11,[r4],#2 ;@ r11=register mask\n");\r
301 \r
302   ot("\n");\r
303   ot(";@ Get the address into r9:\n");\r
304   EaCalc(9,0x003f,cea,size);\r
305 \r
306   ot(";@ r10=Register Index*4:\n");\r
307   if (decr) ot("  mov r10,#0x3c ;@ order reversed for -(An)\n");\r
308   else      ot("  mov r10,#0\n");\r
309   \r
310   ot("\n");\r
311   ot("MoreReg%.4x%s\n",op, ms?"":":");\r
312 \r
313   ot("  tst r11,#1\n");\r
314   ot("  beq SkipReg%.4x\n",op);\r
315   ot("\n");\r
316 \r
317   if (decr) ot("  sub r9,r9,#%d ;@ Pre-decrement address\n",1<<size);\r
318 \r
319   if (dir)\r
320   {\r
321     ot("  ;@ Copy memory to register:\n",1<<size);\r
322     EaRead (9,0,ea,size);\r
323     ot("  str r0,[r7,r10] ;@ Save value into Dn/An\n");\r
324   }\r
325   else\r
326   {\r
327     ot("  ;@ Copy register to memory:\n",1<<size);\r
328     ot("  ldr r1,[r7,r10] ;@ Load value from Dn/An\n");\r
329     EaWrite(9,1,ea,size);\r
330   }\r
331 \r
332   if (decr==0) ot("  add r9,r9,#%d ;@ Post-increment address\n",1<<size);\r
333 \r
334   ot("  sub r5,r5,#%d ;@ Take some cycles\n",2<<size);\r
335   ot("\n");\r
336   ot("SkipReg%.4x%s\n",op, ms?"":":");\r
337   ot("  movs r11,r11,lsr #1;@ Shift mask:\n");\r
338   ot("  add r10,r10,#%d ;@ r10=Next Register\n",decr?-4:4);\r
339   ot("  bne MoreReg%.4x\n",op);\r
340   ot("\n");\r
341 \r
342   if (change)\r
343   {\r
344     ot(";@ Write back address:\n");\r
345     EaCalc (0,0x0007,8|(ea&7),2);\r
346     EaWrite(0,     9,8|(ea&7),2);\r
347   }\r
348 \r
349   ot("  ldmia sp!,{r9} ;@ Pop r9\n");\r
350   ot("\n");\r
351 \r
352        if (ea<0x10) { }\r
353   else if (ea<0x18) Cycles=16; // (a0)\r
354   else if (ea<0x20) Cycles= 0; // (a0)+ ?\r
355   else if (ea<0x28) Cycles= 8; //-(a0)\r
356   else if (ea<0x30) Cycles=24; // ($3333,a0)\r
357   else if (ea<0x38) Cycles=28; // ($33,a0,d3.w*2)\r
358   else if (ea<0x39) Cycles=24; // $3333.w\r
359   else if (ea<0x3a) Cycles=28; // $33333333.l\r
360 \r
361   OpEnd();\r
362 \r
363   return 0;\r
364 }\r
365 \r
366 // --------------------- Opcodes 0x4e60+ ---------------------\r
367 // Emit a Move USP opcode, 01001110 0110dnnn move An to/from USP\r
368 int OpMoveUsp(int op)\r
369 {\r
370   int use=0,dir=0;\r
371 \r
372   dir=(op>>3)&1; // Direction\r
373   use=op&~0x0007; // Use same opcode for all An\r
374 \r
375   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
376 \r
377   OpStart(op); Cycles=4;\r
378 \r
379   ot("  ldrb r0,[r7,#0x44] ;@ Get SR\n");\r
380   ot("  tst r0,#0x20 ;@ Check we are in supervisor mode\n");\r
381   ot("  beq WrongMode%.4x ;@ No\n",op);\r
382   ot("\n");\r
383 \r
384   if (dir)\r
385   {\r
386     EaCalc (0,0x0007,8,2);\r
387     ot("  ldr r1,[r7,#0x48] ;@ Get from USP\n\n");\r
388     EaWrite(0,     1,8,2);\r
389   }\r
390   else\r
391   {\r
392     EaCalc (0,0x0007,8,2);\r
393     EaRead (0,     0,8,2);\r
394     ot("  str r0,[r7,#0x48] ;@ Put in USP\n\n");\r
395   }\r
396     \r
397   OpEnd();\r
398 \r
399   ot("WrongMode%.4x%s\n",op,ms?"":":");\r
400   ot(";@ todo - cause an exception\n");\r
401   OpEnd();\r
402 \r
403   return 0;\r
404 }\r
405 \r
406 // --------------------- Opcodes 0x7000+ ---------------------\r
407 // Emit a Move Quick opcode, 0111nnn0 dddddddd  moveq #dd,Dn\r
408 int OpMoveq(int op)\r
409 {\r
410   int use=0;\r
411 \r
412   use=op&0xf100; // Use same opcode for all values\r
413   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
414 \r
415   OpStart(op); Cycles=4;\r
416 \r
417   ot("  movs r0,r8,asl #24\n");\r
418   ot("  and r1,r8,#0x0e00\n");\r
419   ot("  mov r0,r0,asr #24 ;@ Sign extended Quick value\n");\r
420   ot("  mrs r9,cpsr ;@ r9=NZ flags\n");\r
421   ot("  str r0,[r7,r1,lsr #7] ;@ Store into Dn\n");\r
422   ot("\n");\r
423 \r
424   OpEnd();\r
425 \r
426   return 0;\r
427 }\r
428 \r
429 // --------------------- Opcodes 0xc140+ ---------------------\r
430 // Emit a Exchange opcode:\r
431 // 1100ttt1 01000sss  exg ds,dt\r
432 // 1100ttt1 01001sss  exg as,at\r
433 // 1100ttt1 10001sss  exg as,dt\r
434 int OpExg(int op)\r
435 {\r
436   int use=0,type=0;\r
437 \r
438   type=op&0xf8;\r
439 \r
440   if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode\r
441 \r
442   use=op&0xf1f8; // Use same opcode for all values\r
443   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
444 \r
445   OpStart(op); Cycles=6;\r
446 \r
447   ot("  and r10,r8,#0x0e00 ;@ Find T register\n");\r
448   ot("  and r11,r8,#0x000f ;@ Find S register\n");\r
449   if (type==0x48) ot("  orr r10,r10,#0x1000 ;@ T is an address register\n");\r
450   ot("\n");\r
451   ot("  ldr r0,[r7,r10,lsr #7] ;@ Get T\n");\r
452   ot("  ldr r1,[r7,r11,lsl #2] ;@ Get S\n");\r
453   ot("\n");\r
454   ot("  str r0,[r7,r11,lsl #2] ;@ T->S\n");\r
455   ot("  str r1,[r7,r10,lsr #7] ;@ S->T\n");  \r
456   ot("\n");\r
457 \r
458   OpEnd();\r
459   \r
460   return 0;\r
461 }\r