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