added copyright line to top of source files next to license information
[cyclone68000.git] / Cyclone / OpMove.cpp
CommitLineData
6003a768 1\r
619b1824 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 0x1000+ ---------------------\r
14// Emit a Move opcode, 00xxdddd ddssssss\r
15int 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
71int 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
108void 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
125void 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
142static 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
150static 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
158int 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
215int 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
249int 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
278int 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
370int 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
410int 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
436int 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