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