license info at top of Cyclone source files
[cyclone68000.git] / Cyclone / OpMove.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 0x1000+ ---------------------\r
12// Emit a Move opcode, 00xxdddd ddssssss\r
13int 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
69int 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
106void 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
123void 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
140static 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
148static 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
156int 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
213int 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
247int 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
276int 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
368int 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
408int 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
434int 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