initial import
[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   CheckPc();\r
62 }\r
63 \r
64 int 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
84 int 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
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(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
157 int 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
214 int 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
270 static 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
277 int 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
338 int 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