first check-in of Cyclone 0.069 under GPLv2 and MAME License. Pico Disa.c/h included too
[cyclone68000.git] / Cyclone / OpMove.cpp
1 \r
2 #include "app.h"\r
3 \r
4 // --------------------- Opcodes 0x1000+ ---------------------\r
5 // Emit a Move opcode, 00xxdddd ddssssss\r
6 int 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
62 int 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
99 void 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
116 void 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
133 static 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
141 static 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
149 int 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
206 int 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
240 int 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
269 int 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
361 int 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
401 int 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
427 int 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