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