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