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