optimizations, bugfixes, uae works (but with timing glitches?)
[picodrive.git] / cpu / Cyclone / OpMove.cpp
1 \r
2 #include "app.h"\r
3 \r
4 \r
5 // Pack our flags into r1, in SR/CCR register format\r
6 // trashes r0,r2\r
7 void OpFlagsToReg(int high)\r
8 {\r
9   ot("  ldr r0,[r7,#0x4c]   ;@ X bit\n");\r
10   ot("  mov r1,r9,lsr #28   ;@ ____NZCV\n");\r
11   ot("  eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n");\r
12   ot("  tst r2,#1           ;@ 1 if C!=V\n");\r
13   ot("  eorne r1,r1,#3      ;@ ____NZVC\n");\r
14   ot("\n");\r
15   if (high) ot("  ldrb r2,[r7,#0x44]  ;@ Include SR high\n");\r
16   ot("  and r0,r0,#0x20000000\n");\r
17   ot("  orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n");\r
18   if (high) ot("  orr r1,r1,r2,lsl #8\n");\r
19   ot("\n");\r
20 }\r
21 \r
22 // Convert SR/CRR register in r0 to our flags\r
23 // trashes r0,r1\r
24 void OpRegToFlags(int high)\r
25 {\r
26   ot("  eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");\r
27   ot("  mov r2,r0,lsl #25\n");\r
28   ot("  tst r1,#1           ;@ 1 if C!=V\n");\r
29   ot("  eorne r0,r0,#3      ;@ ___XNZCV\n");\r
30   ot("  str r2,[r7,#0x4c]   ;@ Store X bit\n");\r
31   ot("  mov r9,r0,lsl #28   ;@ r9=NZCV...\n");\r
32 \r
33   if (high)\r
34   {\r
35     ot("  mov r0,r0,ror #8\n");\r
36     ot("  and r0,r0,#0xa7 ;@ only take defined bits\n");\r
37     ot("  strb r0,[r7,#0x44] ;@ Store SR high\n");\r
38   }\r
39   ot("\n");\r
40 }\r
41 \r
42 void SuperEnd(void)\r
43 {\r
44   ot(";@ ----------\n");\r
45   ot(";@ tried execute privileged instruction in user mode\n");\r
46   ot("WrongPrivilegeMode%s\n",ms?"":":");\r
47   ot("  sub r4,r4,#2 ;@ last opcode wasn't executed - go back\n");\r
48   ot("  mov r0,#0x20 ;@ privilege violation\n");\r
49   ot("  bl Exception\n");\r
50   Cycles=34;\r
51   OpEnd(0);\r
52 }\r
53 \r
54 // does OSP and A7 swapping if needed\r
55 // new or old SR (not the one already in [r7,#0x44]) should be passed in r11\r
56 // trashes r0,r11\r
57 void SuperChange(int op,int load_srh)\r
58 {\r
59   ot(";@ A7 <-> OSP?\n");\r
60   if (load_srh)\r
61     ot("  ldr r0,[r7,#0x44] ;@ Get other SR high\n");\r
62   ot("  eor r0,r0,r11\n");\r
63   ot("  tst r0,#0x20\n");\r
64   ot("  beq no_sp_swap%.4x\n",op);\r
65   ot(" ;@ swap OSP and A7:\n");\r
66   ot("  ldr r11,[r7,#0x3C] ;@ Get A7\n");\r
67   ot("  ldr r0, [r7,#0x48] ;@ Get OSP\n");\r
68   ot("  str r11,[r7,#0x48]\n");\r
69   ot("  str r0, [r7,#0x3C]\n");\r
70   ot("no_sp_swap%.4x%s\n", op, ms?"":":");\r
71 }\r
72 \r
73 \r
74 \r
75 // --------------------- Opcodes 0x1000+ ---------------------\r
76 // Emit a Move opcode, 00xxdddd ddssssss\r
77 int OpMove(int op)\r
78 {\r
79   int sea=0,tea=0;\r
80   int size=0,use=0;\r
81   int movea=0;\r
82 \r
83   // Get source and target EA\r
84   sea = op&0x003f;\r
85   tea =(op&0x01c0)>>3;\r
86   tea|=(op&0x0e00)>>9;\r
87 \r
88   if (tea>=8 && tea<0x10) movea=1;\r
89 \r
90   // Find size extension\r
91   switch (op&0x3000)\r
92   {\r
93     default: return 1;\r
94     case 0x1000: size=0; break;\r
95     case 0x3000: size=1; break;\r
96     case 0x2000: size=2; break;\r
97   }\r
98 \r
99   if (size<1 && (movea || EaAn(sea))) return 1; // move.b An,* and movea.b * are invalid\r
100 \r
101   // See if we can do this opcode:\r
102   if (EaCanRead (sea,size)==0) return 1;\r
103   if (EaCanWrite(tea     )==0) return 1;\r
104 \r
105   use=OpBase(op,size);\r
106   if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7\r
107   \r
108   if (tea==0x1f || tea==0x27) use|=0x0e00; // Specific handler for (a7)+ and -(a7)\r
109 \r
110   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
111 \r
112   OpStart(op,sea,tea); Cycles=4;\r
113 \r
114   EaCalcRead(-1,1,sea,size,0x003f);\r
115 \r
116   if (movea==0)\r
117   {\r
118     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");\r
119     ot("  mrs r9,cpsr ;@ r9=NZCV flags\n");\r
120     ot("\n");\r
121   }\r
122 \r
123   if (movea) size=2; // movea always expands to 32-bits\r
124 \r
125 #if SPLIT_MOVEL_PD\r
126   if ((tea&0x38)==0x20 && size==2) { // -(An)\r
127     EaCalc (10,0x0e00,tea,size,0,0);\r
128     ot("  mov r11,r1\n");\r
129     ot("  add r0,r10,#2\n");\r
130     EaWrite(0,     1,tea,1,0x0e00,0,0);\r
131     EaWrite(10,   11,tea,1,0x0e00,1);\r
132   }\r
133   else\r
134 #endif\r
135   {\r
136     EaCalc (0,0x0e00,tea,size,0,0);\r
137     EaWrite(0,     1,tea,size,0x0e00,0,0);\r
138   }\r
139 \r
140 #if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES\r
141   // this is a bit hacky\r
142   if ((tea==0x39||(tea&0x38)==0x10)&&size>=1)\r
143     ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");\r
144 #endif\r
145 \r
146   if((tea&0x38)==0x20) Cycles-=2; // less cycles when dest is -(An)\r
147 \r
148   OpEnd(sea,tea);\r
149   return 0;\r
150 }\r
151 \r
152 // --------------------- Opcodes 0x41c0+ ---------------------\r
153 // Emit an Lea opcode, 0100nnn1 11aaaaaa\r
154 int OpLea(int op)\r
155 {\r
156   int use=0;\r
157   int sea=0,tea=0;\r
158 \r
159   sea= op&0x003f;\r
160   tea=(op&0x0e00)>>9; tea|=8;\r
161 \r
162   if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode\r
163 \r
164   use=OpBase(op,0);\r
165   use&=~0x0e00; // Also use 1 handler for target ?0-7\r
166   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
167 \r
168   OpStart(op,sea,tea);\r
169 \r
170   EaCalc (1,0x003f,sea,0); // Lea\r
171   EaCalc (0,0x0e00,tea,2);\r
172   EaWrite(0,     1,tea,2,0x0e00);\r
173 \r
174   Cycles=Ea_add_ns(g_lea_cycle_table,sea);\r
175 \r
176   OpEnd(sea,tea);\r
177 \r
178   return 0;\r
179 }\r
180 \r
181 // --------------------- Opcodes 0x40c0+ ---------------------\r
182 // Move SR opcode, 01000tt0 11aaaaaa move SR\r
183 int OpMoveSr(int op)\r
184 {\r
185   int type=0,ea=0;\r
186   int use=0,size=1;\r
187 \r
188   type=(op>>9)&3; // from SR, from CCR, to CCR, to SR\r
189   ea=op&0x3f;\r
190 \r
191   if(EaAn(ea)) return 1; // can't use An regs\r
192 \r
193   switch(type)\r
194   {\r
195     case 0:\r
196       if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode:\r
197       break;\r
198 \r
199     case 1:\r
200       return 1; // no such op in 68000\r
201 \r
202     case 2: case 3:\r
203       if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode:\r
204       break;\r
205   }\r
206 \r
207   use=OpBase(op,size);\r
208   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
209 \r
210   // 68000 model allows reading whole SR in user mode (but newer models don't)\r
211   OpStart(op,ea,0,0,type==3);\r
212   Cycles=12;\r
213   if (type==0) Cycles=(ea>=8)?8:6;\r
214 \r
215   if (type==0 || type==1)\r
216   {\r
217     OpFlagsToReg(type==0);\r
218     EaCalc (0,0x003f,ea,size,0,0);\r
219     EaWrite(0,     1,ea,size,0x003f,0,0);\r
220   }\r
221 \r
222   if (type==2 || type==3)\r
223   {\r
224     EaCalcReadNoSE(-1,0,ea,size,0x003f);\r
225     OpRegToFlags(type==3);\r
226     if (type==3) {\r
227       SuperChange(op,0);\r
228     }\r
229   }\r
230 \r
231   OpEnd(ea,0,0,type==3);\r
232 \r
233   return 0;\r
234 }\r
235 \r
236 \r
237 // Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100\r
238 int OpArithSr(int op)\r
239 {\r
240   int type=0,ea=0;\r
241   int use=0,size=0;\r
242 \r
243   type=(op>>9)&5; if (type==4) return 1;\r
244   size=(op>>6)&1; // ccr or sr?\r
245   ea=0x3c;\r
246 \r
247   use=OpBase(op,size);\r
248   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
249 \r
250   OpStart(op,ea,0,0,size!=0); Cycles=16;\r
251 \r
252   EaCalc(10,0x003f,ea,size);\r
253   EaRead(10,    10,ea,size,0x003f);\r
254 \r
255   OpFlagsToReg(size);\r
256   if (type==0) ot("  orr r0,r1,r10\n");\r
257   if (type==1) ot("  and r0,r1,r10\n");\r
258   if (type==5) ot("  eor r0,r1,r10\n");\r
259   OpRegToFlags(size);\r
260   if (size && type!=0) { // we can't enter supervisor mode, nor unmask irqs just by using OR\r
261     SuperChange(op,0);\r
262   }\r
263 \r
264   OpEnd(ea,0,0,size!=0 && type!=0);\r
265 \r
266   return 0;\r
267 }\r
268 \r
269 // --------------------- Opcodes 0x4850+ ---------------------\r
270 // Emit an Pea opcode, 01001000 01aaaaaa\r
271 int OpPea(int op)\r
272 {\r
273   int use=0;\r
274   int ea=0;\r
275 \r
276   ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode\r
277   if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode:\r
278 \r
279   use=OpBase(op,0);\r
280   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
281 \r
282   OpStart(op,ea);\r
283 \r
284   ot("  ldr r10,[r7,#0x3c]\n");\r
285   EaCalc (1,0x003f, ea,0);\r
286   ot("\n");\r
287   ot("  sub r0,r10,#4 ;@ Predecrement A7\n");\r
288   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");\r
289   ot("\n");\r
290   MemHandler(1,2); // Write 32-bit\r
291   ot("\n");\r
292 \r
293   Cycles=6+Ea_add_ns(g_pea_cycle_table,ea);\r
294 \r
295   OpEnd(ea);\r
296 \r
297   return 0;\r
298 }\r
299 \r
300 // --------------------- Opcodes 0x4880+ ---------------------\r
301 // Emit a Movem opcode, 01001d00 1xeeeeee regmask\r
302 int OpMovem(int op)\r
303 {\r
304   int size=0,ea=0,cea=0,dir=0;\r
305   int use=0,decr=0,change=0;\r
306 \r
307   size=((op>>6)&1)+1; // word, long\r
308   ea=op&0x003f;\r
309   dir=(op>>10)&1; // Direction (1==ea2reg)\r
310 \r
311   if (dir) {\r
312     if (ea<0x10 || ea>0x3b || (ea&0x38)==0x20) return 1; // Invalid EA\r
313   } else {\r
314     if (ea<0x10 || ea>0x39 || (ea&0x38)==0x18) return 1;\r
315   }\r
316 \r
317   if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1;\r
318   if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr\r
319 \r
320   cea=ea; if (change) cea=0x10;\r
321 \r
322   use=OpBase(op,size);\r
323   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
324 \r
325   OpStart(op,ea,0,1);\r
326 \r
327   ot("  ldrh r11,[r4],#2 ;@ r11=register mask\n");\r
328 \r
329   ot(";@ r10=Register Index*4:\n");\r
330   if (decr) ot("  mov r10,#0x40 ;@ order reversed for -(An)\n");\r
331   else      ot("  mov r10,#-4\n");\r
332   \r
333   ot("\n");\r
334   ot(";@ Get the address into r6:\n");\r
335   EaCalc(6,0x003f,cea,size);\r
336 \r
337   ot("\n");\r
338   ot("  tst r11,r11\n");        // sanity check\r
339   ot("  beq NoRegs%.4x\n",op);\r
340 \r
341   ot("\n");\r
342   ot("Movemloop%.4x%s\n",op, ms?"":":");\r
343   ot("  add r10,r10,#%d ;@ r10=Next Register\n",decr?-4:4);\r
344   ot("  movs r11,r11,lsr #1\n");\r
345   ot("  bcc Movemloop%.4x\n",op);\r
346   ot("\n");\r
347 \r
348   if (decr) ot("  sub r6,r6,#%d ;@ Pre-decrement address\n",1<<size);\r
349 \r
350   if (dir)\r
351   {\r
352     ot("  ;@ Copy memory to register:\n",1<<size);\r
353     EaRead (6,0,ea,size,0x003f);\r
354     ot("  str r0,[r7,r10] ;@ Save value into Dn/An\n");\r
355   }\r
356   else\r
357   {\r
358     // if (size == 2 && decr && SPLIT_MOVEL_PD) we should do 2xWrite16 here\r
359     // (same as in movel.l ?, -(An)), but as this is not likely to be needed and\r
360     // we do not want the performance hit, we do single Write32 instead.\r
361     ot("  ;@ Copy register to memory:\n",1<<size);\r
362     ot("  ldr r1,[r7,r10] ;@ Load value from Dn/An\n");\r
363     EaWrite(6,1,ea,size,0x003f);\r
364   }\r
365 \r
366   if (decr==0) ot("  add r6,r6,#%d ;@ Post-increment address\n",1<<size);\r
367 \r
368   ot("  sub r5,r5,#%d ;@ Take some cycles\n",2<<size);\r
369   ot("  tst r11,r11\n");\r
370   ot("  bne Movemloop%.4x\n",op);\r
371   ot("\n");\r
372 \r
373   if (change)\r
374   {\r
375     ot(";@ Write back address:\n");\r
376     EaCalc (0,0x0007,8|(ea&7),2);\r
377     EaWrite(0,     6,8|(ea&7),2,0x0007);\r
378   }\r
379 \r
380   ot("NoRegs%.4x%s\n",op, ms?"":":");\r
381   ot("  ldr r6,=CycloneJumpTab ;@ restore Opcode Jump table\n");\r
382   ot("\n");\r
383 \r
384   if(dir) { // er\r
385          if (ea==0x3a) Cycles=16; // ($nn,PC)\r
386     else if (ea==0x3b) Cycles=18; // ($nn,pc,Rn)\r
387     else Cycles=12;\r
388   } else {\r
389     Cycles=8;\r
390   }\r
391 \r
392   Cycles+=Ea_add_ns(g_movem_cycle_table,ea);\r
393 \r
394   OpEnd(ea,0,1);\r
395   ltorg();\r
396   ot("\n");\r
397 \r
398   return 0;\r
399 }\r
400 \r
401 // --------------------- Opcodes 0x4e60+ ---------------------\r
402 // Emit a Move USP opcode, 01001110 0110dnnn move An to/from USP\r
403 int OpMoveUsp(int op)\r
404 {\r
405   int use=0,dir=0;\r
406 \r
407   dir=(op>>3)&1; // Direction\r
408   use=op&~0x0007; // Use same opcode for all An\r
409 \r
410   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
411 \r
412   OpStart(op,0,0,0,1); Cycles=4;\r
413 \r
414   if (dir)\r
415   {\r
416     ot("  ldr r1,[r7,#0x48] ;@ Get from USP\n\n");\r
417     EaCalc (0,0x000f,8,2,1);\r
418     EaWrite(0,     1,8,2,0x000f,1);\r
419   }\r
420   else\r
421   {\r
422     EaCalc (0,0x000f,8,2,1);\r
423     EaRead (0,     0,8,2,0x000f,1);\r
424     ot("  str r0,[r7,#0x48] ;@ Put in USP\n\n");\r
425   }\r
426     \r
427   OpEnd();\r
428 \r
429   return 0;\r
430 }\r
431 \r
432 // --------------------- Opcodes 0x7000+ ---------------------\r
433 // Emit a Move Quick opcode, 0111nnn0 dddddddd  moveq #dd,Dn\r
434 int OpMoveq(int op)\r
435 {\r
436   int use=0;\r
437 \r
438   use=op&0xf100; // Use same opcode for all values\r
439   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
440 \r
441   OpStart(op); Cycles=4;\r
442 \r
443   ot("  movs r0,r8,asl #24\n");\r
444   ot("  and r1,r8,#0x0e00\n");\r
445   ot("  mov r0,r0,asr #24 ;@ Sign extended Quick value\n");\r
446   ot("  mrs r9,cpsr ;@ r9=NZ flags\n");\r
447   ot("  str r0,[r7,r1,lsr #7] ;@ Store into Dn\n");\r
448   ot("\n");\r
449 \r
450   OpEnd();\r
451 \r
452   return 0;\r
453 }\r
454 \r
455 // --------------------- Opcodes 0xc140+ ---------------------\r
456 // Emit a Exchange opcode:\r
457 // 1100ttt1 01000sss  exg ds,dt\r
458 // 1100ttt1 01001sss  exg as,at\r
459 // 1100ttt1 10001sss  exg as,dt\r
460 int OpExg(int op)\r
461 {\r
462   int use=0,type=0;\r
463 \r
464   type=op&0xf8;\r
465 \r
466   if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode\r
467 \r
468   use=op&0xf1f8; // Use same opcode for all values\r
469   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
470 \r
471   OpStart(op); Cycles=6;\r
472 \r
473   ot("  and r10,r8,#0x0e00 ;@ Find T register\n");\r
474   ot("  and r11,r8,#0x000f ;@ Find S register\n");\r
475   if (type==0x48) ot("  orr r10,r10,#0x1000 ;@ T is an address register\n");\r
476   ot("\n");\r
477   ot("  ldr r0,[r7,r10,lsr #7] ;@ Get T\n");\r
478   ot("  ldr r1,[r7,r11,lsl #2] ;@ Get S\n");\r
479   ot("\n");\r
480   ot("  str r0,[r7,r11,lsl #2] ;@ T->S\n");\r
481   ot("  str r1,[r7,r10,lsr #7] ;@ S->T\n");  \r
482   ot("\n");\r
483 \r
484   OpEnd();\r
485   \r
486   return 0;\r
487 }\r
488 \r
489 // ------------------------- movep -------------------------------\r
490 // 0000ddd1 0z001sss\r
491 // 0000sss1 1z001ddd (to mem)\r
492 int OpMovep(int op)\r
493 {\r
494   int ea=0,rea=0;\r
495   int size=1,use=0,dir,aadd=0;\r
496 \r
497   use=op&0xf1f8;\r
498   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler (for all dests, srcs)\r
499 \r
500   // Get EA\r
501   ea = (op&0x0007)|0x28;\r
502   rea= (op&0x0e00)>>9;\r
503   dir = (op>>7)&1;\r
504 \r
505   // Find size extension\r
506   if(op&0x0040) size=2;\r
507 \r
508   OpStart(op,ea);\r
509   \r
510   if(dir) { // reg to mem\r
511     EaCalcReadNoSE(-1,11,rea,size,0x0e00);\r
512 \r
513     EaCalc(10,0x000f,ea,size);\r
514     if(size==2) { // if operand is long\r
515       ot("  mov r1,r11,lsr #24 ;@ first byte\n");\r
516       EaWrite(10,1,ea,0,0x000f); // store first byte\r
517       ot("  add r0,r10,#%i\n",(aadd+=2));\r
518       ot("  mov r1,r11,lsr #16 ;@ second byte\n");\r
519       EaWrite(0,1,ea,0,0x000f); // store second byte\r
520       ot("  add r0,r10,#%i\n",(aadd+=2));\r
521     } else {\r
522       ot("  mov r0,r10\n");\r
523     }\r
524     ot("  mov r1,r11,lsr #8 ;@ first or third byte\n");\r
525     EaWrite(0,1,ea,0,0x000f);\r
526     ot("  add r0,r10,#%i\n",(aadd+=2));\r
527     ot("  and r1,r11,#0xff\n");\r
528     EaWrite(0,1,ea,0,0x000f);\r
529   } else { // mem to reg\r
530     EaCalc(10,0x000f,ea,size,1);\r
531     EaRead(10,11,ea,0,0x000f,1); // read first byte\r
532     ot("  add r0,r10,#2\n");\r
533     EaRead(0,1,ea,0,0x000f,1); // read second byte\r
534     if(size==2) { // if operand is long\r
535       ot("  orr r11,r11,r1,lsr #8 ;@ second byte\n");\r
536       ot("  add r0,r10,#4\n");\r
537       EaRead(0,1,ea,0,0x000f,1);\r
538       ot("  orr r11,r11,r1,lsr #16 ;@ third byte\n");\r
539       ot("  add r0,r10,#6\n");\r
540       EaRead(0,1,ea,0,0x000f,1);\r
541       ot("  orr r1,r11,r1,lsr #24 ;@ fourth byte\n");\r
542     } else {\r
543       ot("  orr r1,r11,r1,lsr #8 ;@ second byte\n");\r
544     }\r
545     // store the result\r
546     EaCalc(11,0x0e00,rea,size,1);      // reg number -> r11\r
547     EaWrite(11,1,rea,size,0x0e00,1);\r
548   }\r
549 \r
550   Cycles=(size==2)?24:16;\r
551   OpEnd(ea);\r
552 \r
553   return 0;\r
554 }\r
555 \r
556 // Emit a Stop/Reset opcodes, 01001110 011100t0 imm\r
557 int OpStopReset(int op)\r
558 {\r
559   int type=(op>>1)&1; // stop/reset\r
560 \r
561   OpStart(op,0,0,0,1);\r
562 \r
563   if(type) {\r
564     // copy immediate to SR, stop the CPU and eat all remaining cycles.\r
565     ot("  ldrh r0,[r4],#2 ;@ Fetch the immediate\n");\r
566     OpRegToFlags(1);\r
567     SuperChange(op,0);\r
568 \r
569     ot("\n");\r
570 \r
571     ot("  mov r0,#1\n");\r
572     ot("  str r0,[r7,#0x58] ;@ stopped\n");\r
573     ot("\n");\r
574 \r
575     ot("  mov r5,#0 ;@ eat cycles\n");\r
576     Cycles = 4;\r
577     ot("\n");\r
578   }\r
579   else\r
580   {\r
581     Cycles = 132;\r
582 #if USE_RESET_CALLBACK\r
583     ot("  str r4,[r7,#0x40] ;@ Save PC\n");\r
584     ot("  mov r1,r9,lsr #28\n");\r
585     ot("  strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");\r
586     ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");\r
587     ot("  ldr r11,[r7,#0x90] ;@ ResetCallback\n");\r
588     ot("  tst r11,r11\n");\r
589     ot("  movne lr,pc\n");\r
590     ot("  bxne r11 ;@ call ResetCallback if it is defined\n");\r
591     ot("  ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");\r
592     ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");\r
593     ot("  ldr r4,[r7,#0x40] ;@ Load PC\n");\r
594     ot("  mov r9,r9,lsl #28\n");\r
595     ot("\n");\r
596 #endif\r
597   }\r
598 \r
599   OpEnd();\r
600 \r
601   return 0;\r
602 }\r
603 \r