b5e2d80c0a868c81e1deeb6650f2581a4a60a936
[cyclone68000.git] / Cyclone / OpBranch.cpp
1 \r
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
9 #include "app.h"\r
10 \r
11 static void CheckPc()\r
12 {\r
13   ot(";@ Check Memory Base+pc (r4)\n");\r
14   ot("  add lr,pc,#4\n");\r
15   ot("  mov r0,r4\n");\r
16   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");\r
17   ot("  mov r4,r0\n");\r
18   ot("\n");\r
19 }\r
20 \r
21 // Push 32-bit value in r1 - trashes r0-r3\r
22 void OpPush32()\r
23 {\r
24   ot(";@ Push r1 onto stack\n");\r
25   ot("  ldr r0,[r7,#0x3c]\n");\r
26   ot("  sub r0,r0,#4 ;@ Predecrement A7\n");\r
27   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");\r
28   MemHandler(1,2);\r
29   ot("\n");\r
30 }\r
31 \r
32 // Push SR - trashes r0-r3\r
33 void OpPushSr(int high)\r
34 {\r
35   ot(";@ Push SR:\n");\r
36   OpFlagsToReg(high);\r
37   ot("  ldr r0,[r7,#0x3c]\n");\r
38   ot("  sub r0,r0,#2 ;@ Predecrement A7\n");\r
39   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");\r
40   MemHandler(1,1);\r
41   ot("\n");\r
42 }\r
43 \r
44 // Pop SR - trashes r0-r3\r
45 static void PopSr(int high)\r
46 {\r
47   ot(";@ Pop SR:\n");\r
48   ot("  ldr r0,[r7,#0x3c]\n");\r
49   ot("  add r1,r0,#2 ;@ Postincrement A7\n");\r
50   ot("  str r1,[r7,#0x3c] ;@ Save A7\n");\r
51   MemHandler(0,1);\r
52   ot("\n");\r
53   OpRegToFlags(high);\r
54 }\r
55 \r
56 // Pop PC - assumes r10=Memory Base - trashes r0-r3\r
57 static void PopPc()\r
58 {\r
59   ot(";@ Pop PC:\n");\r
60   ot("  ldr r0,[r7,#0x3c]\n");\r
61   ot("  add r1,r0,#4 ;@ Postincrement A7\n");\r
62   ot("  str r1,[r7,#0x3c] ;@ Save A7\n");\r
63   MemHandler(0,2);\r
64   ot("  add r4,r0,r10 ;@ r4=Memory Base+PC\n");\r
65   ot("\n");\r
66   CheckPc();\r
67 }\r
68 \r
69 int OpTrap(int op)\r
70 {\r
71   int use=0;\r
72 \r
73   use=op&~0xf;\r
74   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
75 \r
76   OpStart(use);\r
77   ot("  and r0,r8,#0xf ;@ Get trap number\n");\r
78   ot("  orr r0,r0,#0x20\n");\r
79   ot("  mov r0,r0,asl #2\n");\r
80   ot("  str r0,[r7,#0x50] ;@ Save Exception Vector\n");\r
81   ot("  bl Exception\n");\r
82   ot("\n");\r
83 \r
84   Cycles=38; OpEnd();\r
85 \r
86   return 0;\r
87 }\r
88 \r
89 // --------------------- Opcodes 0x4e50+ ---------------------\r
90 int OpLink(int op)\r
91 {\r
92   int use=0;\r
93 \r
94   use=op&~7;\r
95   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
96 \r
97   OpStart(use);\r
98 \r
99   ot(";@ Get An\n");\r
100   EaCalc(10, 7, 8, 2);\r
101   EaRead(10, 1, 8, 2, 1);\r
102 \r
103   ot("  ldr r0,[r7,#0x3c] ;@ Get A7\n");\r
104   ot("  sub r0,r0,#4 ;@ A7-=4\n");\r
105   ot("  mov r11,r0\n");\r
106   ot("\n");\r
107   \r
108   ot(";@ Write An to Stack\n");\r
109   MemHandler(1,2);\r
110 \r
111   ot(";@ Save to An\n");\r
112   EaWrite(10,11, 8, 2, 1);\r
113 \r
114   ot(";@ Get offset:\n");\r
115   EaCalc(0,0,0x3c,1);\r
116   EaRead(0,0,0x3c,1);\r
117 \r
118   ot("  add r11,r11,r0 ;@ Add offset to A7\n");\r
119   ot("  str r11,[r7,#0x3c]\n");\r
120   ot("\n");\r
121 \r
122   Cycles=16;\r
123   OpEnd();\r
124   return 0;\r
125 }\r
126 \r
127 // --------------------- Opcodes 0x4e58+ ---------------------\r
128 int OpUnlk(int op)\r
129 {\r
130   int use=0;\r
131 \r
132   use=op&~7;\r
133   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
134 \r
135   OpStart(use);\r
136 \r
137   ot(";@ Get An\n");\r
138   EaCalc(10, 7, 8, 2);\r
139   EaRead(10, 0, 8, 2, 1);\r
140 \r
141   ot("  add r11,r0,#4 ;@ A7+=4\n");\r
142   ot("\n");\r
143   ot(";@ Pop An from stack:\n");\r
144   MemHandler(0,2);\r
145   ot("\n");\r
146   ot("  str r11,[r7,#0x3c] ;@ Save A7\n");\r
147   ot("\n");\r
148   ot(";@ An = value from stack:\n");\r
149   EaWrite(10, 0, 8, 2, 1);\r
150   \r
151   Cycles=12;\r
152   OpEnd();\r
153   return 0;\r
154 }\r
155 \r
156 // --------------------- Opcodes 0x4e70+ ---------------------\r
157 int Op4E70(int op)\r
158 {\r
159   int type=0;\r
160 \r
161   type=op&7;\r
162   // 01001110 01110ttt, reset/nop/stop/rte/rtd/rts/trapv/rtr\r
163   if (type==1) { OpStart(op); Cycles=4; OpEnd(); return 0; } // nop\r
164 \r
165   if (type==3 || type==7) // rte/rtr\r
166   {\r
167     OpStart(op); Cycles=20;\r
168     PopSr(type==3);\r
169     ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");\r
170     PopPc();\r
171     if (type==3) CheckInterrupt();\r
172     OpEnd();\r
173     return 0;\r
174   }\r
175 \r
176   if (type==5) // rts\r
177   {\r
178     OpStart(op); Cycles=16;\r
179     ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");\r
180     PopPc();\r
181     OpEnd();\r
182     return 0;\r
183   }\r
184 \r
185   return 1;\r
186 }\r
187 \r
188 // --------------------- Opcodes 0x4e80+ ---------------------\r
189 // Emit a Jsr/Jmp opcode, 01001110 1mEEEeee\r
190 int OpJsr(int op)\r
191 {\r
192   int use=0;\r
193   int sea=0;\r
194 \r
195   sea=op&0x003f;\r
196 \r
197   // See if we can do this opcode:\r
198   if (EaCanRead(sea,-1)==0) return 1;\r
199 \r
200   use=OpBase(op);\r
201   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
202 \r
203   OpStart(op); Cycles=14; // Correct?\r
204 \r
205   ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");\r
206   ot("\n");\r
207   EaCalc(0,0x003f,sea,0);\r
208 \r
209   ot(";@ Jump - Get new PC from r0\n");\r
210   if (op&0x40)\r
211   {\r
212     // Jmp - Get new PC from r0\r
213     ot("  add r4,r0,r10 ;@ r4 = Memory Base + New PC\n");\r
214     ot("\n");\r
215   }\r
216   else\r
217   {\r
218     ot(";@ Jsr - Push old PC first\n");\r
219     ot("  sub r1,r4,r10 ;@ r1 = Old PC\n");\r
220     ot("  add r4,r0,r10 ;@ r4 = Memory Base + New PC\n");\r
221     ot("\n");\r
222     OpPush32();\r
223 \r
224     Cycles+=8;\r
225   }\r
226 \r
227   if (Amatch && sea==0x10) Cycles-=2; // (An) Correct?\r
228 \r
229   CheckPc();\r
230 \r
231   OpEnd();\r
232 \r
233   return 0;\r
234 }\r
235 \r
236 // --------------------- Opcodes 0x50c8+ ---------------------\r
237 \r
238 // ARM version of 68000 condition codes:\r
239 static char *Cond[16]=\r
240 {\r
241   "",  "",  "hi","ls","cc","cs","ne","eq",\r
242   "vc","vs","pl","mi","ge","lt","gt","le"\r
243 };\r
244 \r
245 // Emit a Dbra opcode, 0101cccc 11001nnn vv\r
246 int OpDbra(int op)\r
247 {\r
248   int use=0;\r
249   int cc=0;\r
250 \r
251   use=op&~7; // Use same handler\r
252   cc=(op>>8)&15;\r
253   \r
254   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
255   OpStart(op); Cycles=10;\r
256 \r
257   ot(";@ Decrement Dn.w\n");\r
258   ot("  and r1,r8,#0x0007\n");\r
259   ot("  mov r1,r1,lsl #2\n");\r
260   ot("  ldrsh r0,[r7,r1]\n");\r
261   ot("  sub r0,r0,#1\n");\r
262   ot("  strh r0,[r7,r1]\n");\r
263   ot("\n");\r
264 \r
265   if (cc>=2)\r
266   {\r
267     ot(";@ Is the condition true?\n");\r
268     if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");\r
269     ot("  msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");\r
270     if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000\n");\r
271     ot(";@ If so, don't dbra\n");\r
272     ot("  b%s DbraEnd%.4x\n",Cond[cc],op);\r
273     ot("\n");\r
274   }\r
275 \r
276   ot(";@ Check if Dn.w is -1\n");\r
277   ot("  cmps r0,#-1\n");\r
278   ot("  beq DbraEnd%.4x\n",op);\r
279   ot("\n");\r
280 \r
281   ot(";@ Get Branch offset:\n");\r
282   ot("  ldrsh r0,[r4]\n");\r
283   ot("  add r4,r4,r0 ;@ r4 = New PC\n");\r
284   ot("\n");\r
285   OpEnd();\r
286   \r
287   ot("DbraEnd%.4x%s\n", op, ms?"":":");\r
288   Cycles+=2;\r
289   ot("  add r4,r4,#2 ;@ Skip branch offset\n");\r
290   ot("\n");\r
291   OpEnd();\r
292 \r
293   return 0;\r
294 }\r
295 \r
296 // --------------------- Opcodes 0x6000+ ---------------------\r
297 // Emit a Branch opcode 0110cccc nn  (cccc=condition)\r
298 int OpBranch(int op)\r
299 {\r
300   int size=0,use=0;\r
301   int offset=0;\r
302   int cc=0;\r
303 \r
304   offset=(char)(op&0xff);\r
305   cc=(op>>8)&15;\r
306 \r
307   // Special offsets:\r
308   if (offset==0)  size=1;\r
309   if (offset==-1) size=2;\r
310 \r
311   if (size) use=op; // 16-bit or 32-bit\r
312   else use=(op&0xff00)+1; // Use same opcode for all 8-bit branches\r
313 \r
314   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
315   OpStart(op); Cycles=10; // Assume branch taken\r
316 \r
317   ot(";@ Get Branch offset:\n");\r
318   if (size)\r
319   {\r
320     EaCalc(0,0,0x3c,size);\r
321     EaRead(0,0,0x3c,size);\r
322     if (Amatch && size==1) Cycles-=4;\r
323   }\r
324 \r
325   if (size==0) ot("  mov r0,r8,asl #24 ;@ Shift 8-bit signed offset up...\n\n");\r
326 \r
327   if (cc>=2)\r
328   {\r
329     ot(";@ Is the condition true?\n");\r
330     if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");\r
331     ot("  msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");\r
332     if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000\n");\r
333 \r
334     if (size==0) ot("  mov r0,r0,asr #24 ;@ ...shift down\n\n");\r
335 \r
336     ot("  b%s DontBranch%.4x\n",Cond[cc^1],op);\r
337 \r
338     ot("\n");\r
339   }\r
340   else\r
341   {\r
342     if (size==0) ot("  mov r0,r0,asr #24 ;@ ...shift down\n\n");\r
343   }\r
344 \r
345   ot(";@ Branch taken - Add on r0 to PC\n");\r
346 \r
347   if (cc==1)\r
348   {\r
349     ot(";@ Bsr - remember old PC\n");\r
350     ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");\r
351     ot("  sub r1,r4,r10 ;@ r1 = Old PC\n");\r
352     ot("\n");\r
353     if (size) ot("  sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<<size);\r
354     ot("  add r4,r4,r0 ;@ r4 = New PC\n");\r
355     ot("\n");\r
356     OpPush32();\r
357     Cycles+=8;\r
358   }\r
359   else\r
360   {\r
361     if (size) ot("  sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<<size);\r
362     ot("  add r4,r4,r0 ;@ r4 = New PC\n");\r
363     ot("\n");\r
364   }\r
365 \r
366   if (offset==0 || offset==-1)\r
367   {\r
368     ot(";@ Branch is quite far, so may be a good idea to check Memory Base+pc\n");\r
369     CheckPc();\r
370   }\r
371 \r
372   OpEnd();\r
373 \r
374   if (cc>=2)\r
375   {\r
376     ot("DontBranch%.4x%s\n", op, ms?"":":");\r
377     Cycles-=2; // Branch not taken\r
378     OpEnd();\r
379   }\r
380 \r
381   return 0;\r
382 }\r
383 \r