278033780d6c91eecf4891b518750bb9a786bb05
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / assem_arm.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus/PCSX - assem_arm.c                                        *
3  *   Copyright (C) 2009-2011 Ari64                                         *
4  *   Copyright (C) 2010-2021 GraÅžvydas "notaz" Ignotas                     *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #define FLAGLESS
23 #include "../gte.h"
24 #undef FLAGLESS
25 #include "../gte_arm.h"
26 #include "../gte_neon.h"
27 #include "pcnt.h"
28 #include "arm_features.h"
29
30 #ifndef __MACH__
31 #define CALLER_SAVE_REGS 0x100f
32 #else
33 #define CALLER_SAVE_REGS 0x120f
34 #endif
35
36 #define unused __attribute__((unused))
37
38 #ifdef DRC_DBG
39 #pragma GCC diagnostic ignored "-Wunused-function"
40 #pragma GCC diagnostic ignored "-Wunused-variable"
41 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
42 #endif
43
44 void indirect_jump_indexed();
45 void indirect_jump();
46 void do_interrupt();
47 void jump_vaddr_r0();
48 void jump_vaddr_r1();
49 void jump_vaddr_r2();
50 void jump_vaddr_r3();
51 void jump_vaddr_r4();
52 void jump_vaddr_r5();
53 void jump_vaddr_r6();
54 void jump_vaddr_r7();
55 void jump_vaddr_r8();
56 void jump_vaddr_r9();
57 void jump_vaddr_r10();
58 void jump_vaddr_r12();
59
60 void * const jump_vaddr_reg[16] = {
61   jump_vaddr_r0,
62   jump_vaddr_r1,
63   jump_vaddr_r2,
64   jump_vaddr_r3,
65   jump_vaddr_r4,
66   jump_vaddr_r5,
67   jump_vaddr_r6,
68   jump_vaddr_r7,
69   jump_vaddr_r8,
70   jump_vaddr_r9,
71   jump_vaddr_r10,
72   0,
73   jump_vaddr_r12,
74   0,
75   0,
76   0
77 };
78
79 void invalidate_addr_r0();
80 void invalidate_addr_r1();
81 void invalidate_addr_r2();
82 void invalidate_addr_r3();
83 void invalidate_addr_r4();
84 void invalidate_addr_r5();
85 void invalidate_addr_r6();
86 void invalidate_addr_r7();
87 void invalidate_addr_r8();
88 void invalidate_addr_r9();
89 void invalidate_addr_r10();
90 void invalidate_addr_r12();
91
92 const u_int invalidate_addr_reg[16] = {
93   (int)invalidate_addr_r0,
94   (int)invalidate_addr_r1,
95   (int)invalidate_addr_r2,
96   (int)invalidate_addr_r3,
97   (int)invalidate_addr_r4,
98   (int)invalidate_addr_r5,
99   (int)invalidate_addr_r6,
100   (int)invalidate_addr_r7,
101   (int)invalidate_addr_r8,
102   (int)invalidate_addr_r9,
103   (int)invalidate_addr_r10,
104   0,
105   (int)invalidate_addr_r12,
106   0,
107   0,
108   0};
109
110 static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
111
112 /* Linker */
113
114 static void set_jump_target(void *addr, void *target_)
115 {
116   u_int target = (u_int)target_;
117   u_char *ptr = addr;
118   u_int *ptr2=(u_int *)ptr;
119   if(ptr[3]==0xe2) {
120     assert((target-(u_int)ptr2-8)<1024);
121     assert(((uintptr_t)addr&3)==0);
122     assert((target&3)==0);
123     *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
124     //printf("target=%x addr=%p insn=%x\n",target,addr,*ptr2);
125   }
126   else if(ptr[3]==0x72) {
127     // generated by emit_jno_unlikely
128     if((target-(u_int)ptr2-8)<1024) {
129       assert(((uintptr_t)addr&3)==0);
130       assert((target&3)==0);
131       *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
132     }
133     else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) {
134       assert(((uintptr_t)addr&3)==0);
135       assert((target&3)==0);
136       *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00;
137     }
138     else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8);
139   }
140   else {
141     assert((ptr[3]&0x0e)==0xa);
142     *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
143   }
144 }
145
146 // This optionally copies the instruction from the target of the branch into
147 // the space before the branch.  Works, but the difference in speed is
148 // usually insignificant.
149 #if 0
150 static void set_jump_target_fillslot(int addr,u_int target,int copy)
151 {
152   u_char *ptr=(u_char *)addr;
153   u_int *ptr2=(u_int *)ptr;
154   assert(!copy||ptr2[-1]==0xe28dd000);
155   if(ptr[3]==0xe2) {
156     assert(!copy);
157     assert((target-(u_int)ptr2-8)<4096);
158     *ptr2=(*ptr2&0xFFFFF000)|(target-(u_int)ptr2-8);
159   }
160   else {
161     assert((ptr[3]&0x0e)==0xa);
162     u_int target_insn=*(u_int *)target;
163     if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags
164       copy=0;
165     }
166     if((target_insn&0x0c100000)==0x04100000) { // Load
167       copy=0;
168     }
169     if(target_insn&0x08000000) {
170       copy=0;
171     }
172     if(copy) {
173       ptr2[-1]=target_insn;
174       target+=4;
175     }
176     *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
177   }
178 }
179 #endif
180
181 /* Literal pool */
182 static void add_literal(int addr,int val)
183 {
184   assert(literalcount<sizeof(literals)/sizeof(literals[0]));
185   literals[literalcount][0]=addr;
186   literals[literalcount][1]=val;
187   literalcount++;
188 }
189
190 // from a pointer to external jump stub (which was produced by emit_extjump2)
191 // find where the jumping insn is
192 static void *find_extjump_insn(void *stub)
193 {
194   int *ptr=(int *)(stub+4);
195   assert((*ptr&0x0fff0000)==0x059f0000); // ldr rx, [pc, #ofs]
196   u_int offset=*ptr&0xfff;
197   void **l_ptr=(void *)ptr+offset+8;
198   return *l_ptr;
199 }
200
201 // find where external branch is liked to using addr of it's stub:
202 // get address that insn one after stub loads (dyna_linker arg1),
203 // treat it as a pointer to branch insn,
204 // return addr where that branch jumps to
205 static void *get_pointer(void *stub)
206 {
207   //printf("get_pointer(%x)\n",(int)stub);
208   int *i_ptr=find_extjump_insn(stub);
209   assert((*i_ptr&0x0f000000)==0x0a000000);
210   return (u_char *)i_ptr+((*i_ptr<<8)>>6)+8;
211 }
212
213 // Find the "clean" entry point from a "dirty" entry point
214 // by skipping past the call to verify_code
215 static void *get_clean_addr(void *addr)
216 {
217   signed int *ptr = addr;
218   #ifndef HAVE_ARMV7
219   ptr+=4;
220   #else
221   ptr+=6;
222   #endif
223   if((*ptr&0xFF000000)!=0xeb000000) ptr++;
224   assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
225   ptr++;
226   if((*ptr&0xFF000000)==0xea000000) {
227     return (char *)ptr+((*ptr<<8)>>6)+8; // follow jump
228   }
229   return ptr;
230 }
231
232 static int verify_dirty(const u_int *ptr)
233 {
234   #ifndef HAVE_ARMV7
235   u_int offset;
236   // get from literal pool
237   assert((*ptr&0xFFFF0000)==0xe59f0000);
238   offset=*ptr&0xfff;
239   u_int source=*(u_int*)((void *)ptr+offset+8);
240   ptr++;
241   assert((*ptr&0xFFFF0000)==0xe59f0000);
242   offset=*ptr&0xfff;
243   u_int copy=*(u_int*)((void *)ptr+offset+8);
244   ptr++;
245   assert((*ptr&0xFFFF0000)==0xe59f0000);
246   offset=*ptr&0xfff;
247   u_int len=*(u_int*)((void *)ptr+offset+8);
248   ptr++;
249   ptr++;
250   #else
251   // ARMv7 movw/movt
252   assert((*ptr&0xFFF00000)==0xe3000000);
253   u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
254   u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
255   u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
256   ptr+=6;
257   #endif
258   if((*ptr&0xFF000000)!=0xeb000000) ptr++;
259   assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
260   //printf("verify_dirty: %x %x %x\n",source,copy,len);
261   return !memcmp((void *)source,(void *)copy,len);
262 }
263
264 // This doesn't necessarily find all clean entry points, just
265 // guarantees that it's not dirty
266 static int isclean(void *addr)
267 {
268   #ifndef HAVE_ARMV7
269   u_int *ptr=((u_int *)addr)+4;
270   #else
271   u_int *ptr=((u_int *)addr)+6;
272   #endif
273   if((*ptr&0xFF000000)!=0xeb000000) ptr++;
274   if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction
275   if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0;
276   if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_ds) return 0;
277   return 1;
278 }
279
280 // get source that block at addr was compiled from (host pointers)
281 static void get_bounds(void *addr, u_char **start, u_char **end)
282 {
283   u_int *ptr = addr;
284   #ifndef HAVE_ARMV7
285   u_int offset;
286   // get from literal pool
287   assert((*ptr&0xFFFF0000)==0xe59f0000);
288   offset=*ptr&0xfff;
289   u_int source=*(u_int*)((void *)ptr+offset+8);
290   ptr++;
291   //assert((*ptr&0xFFFF0000)==0xe59f0000);
292   //offset=*ptr&0xfff;
293   //u_int copy=*(u_int*)((void *)ptr+offset+8);
294   ptr++;
295   assert((*ptr&0xFFFF0000)==0xe59f0000);
296   offset=*ptr&0xfff;
297   u_int len=*(u_int*)((void *)ptr+offset+8);
298   ptr++;
299   ptr++;
300   #else
301   // ARMv7 movw/movt
302   assert((*ptr&0xFFF00000)==0xe3000000);
303   u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
304   //u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
305   u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
306   ptr+=6;
307   #endif
308   if((*ptr&0xFF000000)!=0xeb000000) ptr++;
309   assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
310   *start=(u_char *)source;
311   *end=(u_char *)source+len;
312 }
313
314 // Allocate a specific ARM register.
315 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
316 {
317   int n;
318   int dirty=0;
319
320   // see if it's already allocated (and dealloc it)
321   for(n=0;n<HOST_REGS;n++)
322   {
323     if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
324       dirty=(cur->dirty>>n)&1;
325       cur->regmap[n]=-1;
326     }
327   }
328
329   cur->regmap[hr]=reg;
330   cur->dirty&=~(1<<hr);
331   cur->dirty|=dirty<<hr;
332   cur->isconst&=~(1<<hr);
333 }
334
335 // Alloc cycle count into dedicated register
336 static void alloc_cc(struct regstat *cur,int i)
337 {
338   alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
339 }
340
341 /* Assembler */
342
343 static unused char regname[16][4] = {
344  "r0",
345  "r1",
346  "r2",
347  "r3",
348  "r4",
349  "r5",
350  "r6",
351  "r7",
352  "r8",
353  "r9",
354  "r10",
355  "fp",
356  "r12",
357  "sp",
358  "lr",
359  "pc"};
360
361 static void output_w32(u_int word)
362 {
363   *((u_int *)out)=word;
364   out+=4;
365 }
366
367 static u_int rd_rn_rm(u_int rd, u_int rn, u_int rm)
368 {
369   assert(rd<16);
370   assert(rn<16);
371   assert(rm<16);
372   return((rn<<16)|(rd<<12)|rm);
373 }
374
375 static u_int rd_rn_imm_shift(u_int rd, u_int rn, u_int imm, u_int shift)
376 {
377   assert(rd<16);
378   assert(rn<16);
379   assert(imm<256);
380   assert((shift&1)==0);
381   return((rn<<16)|(rd<<12)|(((32-shift)&30)<<7)|imm);
382 }
383
384 static u_int genimm(u_int imm,u_int *encoded)
385 {
386   *encoded=0;
387   if(imm==0) return 1;
388   int i=32;
389   while(i>0)
390   {
391     if(imm<256) {
392       *encoded=((i&30)<<7)|imm;
393       return 1;
394     }
395     imm=(imm>>2)|(imm<<30);i-=2;
396   }
397   return 0;
398 }
399
400 static void genimm_checked(u_int imm,u_int *encoded)
401 {
402   u_int ret=genimm(imm,encoded);
403   assert(ret);
404   (void)ret;
405 }
406
407 static u_int genjmp(u_int addr)
408 {
409   if (addr < 3) return 0; // a branch that will be patched later
410   int offset = addr-(int)out-8;
411   if (offset < -33554432 || offset >= 33554432) {
412     SysPrintf("genjmp: out of range: %08x\n", offset);
413     abort();
414     return 0;
415   }
416   return ((u_int)offset>>2)&0xffffff;
417 }
418
419 static unused void emit_breakpoint(void)
420 {
421   assem_debug("bkpt #0\n");
422   //output_w32(0xe1200070);
423   output_w32(0xe7f001f0);
424 }
425
426 static void emit_mov(int rs,int rt)
427 {
428   assem_debug("mov %s,%s\n",regname[rt],regname[rs]);
429   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs));
430 }
431
432 static void emit_movs(int rs,int rt)
433 {
434   assem_debug("movs %s,%s\n",regname[rt],regname[rs]);
435   output_w32(0xe1b00000|rd_rn_rm(rt,0,rs));
436 }
437
438 static void emit_add(int rs1,int rs2,int rt)
439 {
440   assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
441   output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2));
442 }
443
444 static void emit_adcs(int rs1,int rs2,int rt)
445 {
446   assem_debug("adcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
447   output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2));
448 }
449
450 static void emit_neg(int rs, int rt)
451 {
452   assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
453   output_w32(0xe2600000|rd_rn_rm(rt,rs,0));
454 }
455
456 static void emit_sub(int rs1,int rs2,int rt)
457 {
458   assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
459   output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2));
460 }
461
462 static void emit_zeroreg(int rt)
463 {
464   assem_debug("mov %s,#0\n",regname[rt]);
465   output_w32(0xe3a00000|rd_rn_rm(rt,0,0));
466 }
467
468 static void emit_loadlp(u_int imm,u_int rt)
469 {
470   add_literal((int)out,imm);
471   assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
472   output_w32(0xe5900000|rd_rn_rm(rt,15,0));
473 }
474
475 static void emit_movw(u_int imm,u_int rt)
476 {
477   assert(imm<65536);
478   assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
479   output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
480 }
481
482 static void emit_movt(u_int imm,u_int rt)
483 {
484   assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
485   output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
486 }
487
488 static void emit_movimm(u_int imm,u_int rt)
489 {
490   u_int armval;
491   if(genimm(imm,&armval)) {
492     assem_debug("mov %s,#%d\n",regname[rt],imm);
493     output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
494   }else if(genimm(~imm,&armval)) {
495     assem_debug("mvn %s,#%d\n",regname[rt],imm);
496     output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
497   }else if(imm<65536) {
498     #ifndef HAVE_ARMV7
499     assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
500     output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
501     assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
502     output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
503     #else
504     emit_movw(imm,rt);
505     #endif
506   }else{
507     #ifndef HAVE_ARMV7
508     emit_loadlp(imm,rt);
509     #else
510     emit_movw(imm&0x0000FFFF,rt);
511     emit_movt(imm&0xFFFF0000,rt);
512     #endif
513   }
514 }
515
516 static void emit_pcreladdr(u_int rt)
517 {
518   assem_debug("add %s,pc,#?\n",regname[rt]);
519   output_w32(0xe2800000|rd_rn_rm(rt,15,0));
520 }
521
522 static void emit_loadreg(int r, int hr)
523 {
524   if(r&64) {
525     SysPrintf("64bit load in 32bit mode!\n");
526     assert(0);
527     return;
528   }
529   if((r&63)==0)
530     emit_zeroreg(hr);
531   else {
532     int addr = (int)&psxRegs.GPR.r[r];
533     switch (r) {
534     //case HIREG: addr = &hi; break;
535     //case LOREG: addr = &lo; break;
536     case CCREG: addr = (int)&cycle_count; break;
537     case CSREG: addr = (int)&Status; break;
538     case INVCP: addr = (int)&invc_ptr; break;
539     default: assert(r < 34); break;
540     }
541     u_int offset = addr-(u_int)&dynarec_local;
542     assert(offset<4096);
543     assem_debug("ldr %s,fp+%d\n",regname[hr],offset);
544     output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset);
545   }
546 }
547
548 static void emit_storereg(int r, int hr)
549 {
550   if(r&64) {
551     SysPrintf("64bit store in 32bit mode!\n");
552     assert(0);
553     return;
554   }
555   int addr = (int)&psxRegs.GPR.r[r];
556   switch (r) {
557   //case HIREG: addr = &hi; break;
558   //case LOREG: addr = &lo; break;
559   case CCREG: addr = (int)&cycle_count; break;
560   default: assert(r < 34); break;
561   }
562   u_int offset = addr-(u_int)&dynarec_local;
563   assert(offset<4096);
564   assem_debug("str %s,fp+%d\n",regname[hr],offset);
565   output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset);
566 }
567
568 static void emit_test(int rs, int rt)
569 {
570   assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
571   output_w32(0xe1100000|rd_rn_rm(0,rs,rt));
572 }
573
574 static void emit_testimm(int rs,int imm)
575 {
576   u_int armval;
577   assem_debug("tst %s,#%d\n",regname[rs],imm);
578   genimm_checked(imm,&armval);
579   output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval);
580 }
581
582 static void emit_testeqimm(int rs,int imm)
583 {
584   u_int armval;
585   assem_debug("tsteq %s,$%d\n",regname[rs],imm);
586   genimm_checked(imm,&armval);
587   output_w32(0x03100000|rd_rn_rm(0,rs,0)|armval);
588 }
589
590 static void emit_not(int rs,int rt)
591 {
592   assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
593   output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
594 }
595
596 static void emit_and(u_int rs1,u_int rs2,u_int rt)
597 {
598   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
599   output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2));
600 }
601
602 static void emit_or(u_int rs1,u_int rs2,u_int rt)
603 {
604   assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
605   output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2));
606 }
607
608 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
609 {
610   assert(rs<16);
611   assert(rt<16);
612   assert(imm<32);
613   assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
614   output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|(imm<<7));
615 }
616
617 static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
618 {
619   assert(rs<16);
620   assert(rt<16);
621   assert(imm<32);
622   assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
623   output_w32(0xe1800020|rd_rn_rm(rt,rt,rs)|(imm<<7));
624 }
625
626 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
627 {
628   assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
629   output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
630 }
631
632 static void emit_xorsar_imm(u_int rs1,u_int rs2,u_int imm,u_int rt)
633 {
634   assem_debug("eor %s,%s,%s,asr #%d\n",regname[rt],regname[rs1],regname[rs2],imm);
635   output_w32(0xe0200040|rd_rn_rm(rt,rs1,rs2)|(imm<<7));
636 }
637
638 static void emit_addimm(u_int rs,int imm,u_int rt)
639 {
640   assert(rs<16);
641   assert(rt<16);
642   if(imm!=0) {
643     u_int armval;
644     if(genimm(imm,&armval)) {
645       assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm);
646       output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
647     }else if(genimm(-imm,&armval)) {
648       assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-imm);
649       output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
650     #ifdef HAVE_ARMV7
651     }else if(rt!=rs&&(u_int)imm<65536) {
652       emit_movw(imm&0x0000ffff,rt);
653       emit_add(rs,rt,rt);
654     }else if(rt!=rs&&(u_int)-imm<65536) {
655       emit_movw(-imm&0x0000ffff,rt);
656       emit_sub(rs,rt,rt);
657     #endif
658     }else if((u_int)-imm<65536) {
659       assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00);
660       assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
661       output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8));
662       output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
663     }else {
664       do {
665         int shift = (ffs(imm) - 1) & ~1;
666         int imm8 = imm & (0xff << shift);
667         genimm_checked(imm8,&armval);
668         assem_debug("add %s,%s,#0x%x\n",regname[rt],regname[rs],imm8);
669         output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
670         rs = rt;
671         imm &= ~imm8;
672       }
673       while (imm != 0);
674     }
675   }
676   else if(rs!=rt) emit_mov(rs,rt);
677 }
678
679 static void emit_addimm_and_set_flags(int imm,int rt)
680 {
681   assert(imm>-65536&&imm<65536);
682   u_int armval;
683   if(genimm(imm,&armval)) {
684     assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm);
685     output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval);
686   }else if(genimm(-imm,&armval)) {
687     assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],imm);
688     output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval);
689   }else if(imm<0) {
690     assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF00);
691     assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
692     output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8));
693     output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
694   }else{
695     assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF00);
696     assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
697     output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8));
698     output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
699   }
700 }
701
702 static void emit_addimm_no_flags(u_int imm,u_int rt)
703 {
704   emit_addimm(rt,imm,rt);
705 }
706
707 static void emit_addnop(u_int r)
708 {
709   assert(r<16);
710   assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]);
711   output_w32(0xe2800000|rd_rn_rm(r,r,0));
712 }
713
714 static void emit_andimm(int rs,int imm,int rt)
715 {
716   u_int armval;
717   if(imm==0) {
718     emit_zeroreg(rt);
719   }else if(genimm(imm,&armval)) {
720     assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm);
721     output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval);
722   }else if(genimm(~imm,&armval)) {
723     assem_debug("bic %s,%s,#%d\n",regname[rt],regname[rs],imm);
724     output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval);
725   }else if(imm==65535) {
726     #ifndef HAVE_ARMV6
727     assem_debug("bic %s,%s,#FF000000\n",regname[rt],regname[rs]);
728     output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF);
729     assem_debug("bic %s,%s,#00FF0000\n",regname[rt],regname[rt]);
730     output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF);
731     #else
732     assem_debug("uxth %s,%s\n",regname[rt],regname[rs]);
733     output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs));
734     #endif
735   }else{
736     assert(imm>0&&imm<65535);
737     #ifndef HAVE_ARMV7
738     assem_debug("mov r14,#%d\n",imm&0xFF00);
739     output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8));
740     assem_debug("add r14,r14,#%d\n",imm&0xFF);
741     output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0));
742     #else
743     emit_movw(imm,HOST_TEMPREG);
744     #endif
745     assem_debug("and %s,%s,r14\n",regname[rt],regname[rs]);
746     output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG));
747   }
748 }
749
750 static void emit_orimm(int rs,int imm,int rt)
751 {
752   u_int armval;
753   if(imm==0) {
754     if(rs!=rt) emit_mov(rs,rt);
755   }else if(genimm(imm,&armval)) {
756     assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm);
757     output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval);
758   }else{
759     assert(imm>0&&imm<65536);
760     assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
761     assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
762     output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8));
763     output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
764   }
765 }
766
767 static void emit_xorimm(int rs,int imm,int rt)
768 {
769   u_int armval;
770   if(imm==0) {
771     if(rs!=rt) emit_mov(rs,rt);
772   }else if(genimm(imm,&armval)) {
773     assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm);
774     output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval);
775   }else{
776     assert(imm>0&&imm<65536);
777     assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
778     assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
779     output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8));
780     output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
781   }
782 }
783
784 static void emit_shlimm(int rs,u_int imm,int rt)
785 {
786   assert(imm>0);
787   assert(imm<32);
788   //if(imm==1) ...
789   assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
790   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7));
791 }
792
793 static void emit_lsls_imm(int rs,int imm,int rt)
794 {
795   assert(imm>0);
796   assert(imm<32);
797   assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
798   output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
799 }
800
801 static unused void emit_lslpls_imm(int rs,int imm,int rt)
802 {
803   assert(imm>0);
804   assert(imm<32);
805   assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
806   output_w32(0x51b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
807 }
808
809 static void emit_shrimm(int rs,u_int imm,int rt)
810 {
811   assert(imm>0);
812   assert(imm<32);
813   assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
814   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
815 }
816
817 static void emit_sarimm(int rs,u_int imm,int rt)
818 {
819   assert(imm>0);
820   assert(imm<32);
821   assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
822   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7));
823 }
824
825 static void emit_rorimm(int rs,u_int imm,int rt)
826 {
827   assert(imm>0);
828   assert(imm<32);
829   assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
830   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7));
831 }
832
833 static void emit_signextend16(int rs,int rt)
834 {
835   #ifndef HAVE_ARMV6
836   emit_shlimm(rs,16,rt);
837   emit_sarimm(rt,16,rt);
838   #else
839   assem_debug("sxth %s,%s\n",regname[rt],regname[rs]);
840   output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs));
841   #endif
842 }
843
844 static void emit_signextend8(int rs,int rt)
845 {
846   #ifndef HAVE_ARMV6
847   emit_shlimm(rs,24,rt);
848   emit_sarimm(rt,24,rt);
849   #else
850   assem_debug("sxtb %s,%s\n",regname[rt],regname[rs]);
851   output_w32(0xe6af0070|rd_rn_rm(rt,0,rs));
852   #endif
853 }
854
855 static void emit_shl(u_int rs,u_int shift,u_int rt)
856 {
857   assert(rs<16);
858   assert(rt<16);
859   assert(shift<16);
860   //if(imm==1) ...
861   assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
862   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8));
863 }
864
865 static void emit_shr(u_int rs,u_int shift,u_int rt)
866 {
867   assert(rs<16);
868   assert(rt<16);
869   assert(shift<16);
870   assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
871   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8));
872 }
873
874 static void emit_sar(u_int rs,u_int shift,u_int rt)
875 {
876   assert(rs<16);
877   assert(rt<16);
878   assert(shift<16);
879   assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
880   output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
881 }
882
883 static unused void emit_orrshl(u_int rs,u_int shift,u_int rt)
884 {
885   assert(rs<16);
886   assert(rt<16);
887   assert(shift<16);
888   assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
889   output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
890 }
891
892 static unused void emit_orrshr(u_int rs,u_int shift,u_int rt)
893 {
894   assert(rs<16);
895   assert(rt<16);
896   assert(shift<16);
897   assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
898   output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8));
899 }
900
901 static void emit_cmpimm(int rs,int imm)
902 {
903   u_int armval;
904   if(genimm(imm,&armval)) {
905     assem_debug("cmp %s,#%d\n",regname[rs],imm);
906     output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval);
907   }else if(genimm(-imm,&armval)) {
908     assem_debug("cmn %s,#%d\n",regname[rs],imm);
909     output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval);
910   }else if(imm>0) {
911     assert(imm<65536);
912     emit_movimm(imm,HOST_TEMPREG);
913     assem_debug("cmp %s,r14\n",regname[rs]);
914     output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG));
915   }else{
916     assert(imm>-65536);
917     emit_movimm(-imm,HOST_TEMPREG);
918     assem_debug("cmn %s,r14\n",regname[rs]);
919     output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG));
920   }
921 }
922
923 static void emit_cmovne_imm(int imm,int rt)
924 {
925   assem_debug("movne %s,#%d\n",regname[rt],imm);
926   u_int armval;
927   genimm_checked(imm,&armval);
928   output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval);
929 }
930
931 static void emit_cmovl_imm(int imm,int rt)
932 {
933   assem_debug("movlt %s,#%d\n",regname[rt],imm);
934   u_int armval;
935   genimm_checked(imm,&armval);
936   output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval);
937 }
938
939 static void emit_cmovb_imm(int imm,int rt)
940 {
941   assem_debug("movcc %s,#%d\n",regname[rt],imm);
942   u_int armval;
943   genimm_checked(imm,&armval);
944   output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
945 }
946
947 static void emit_cmovae_imm(int imm,int rt)
948 {
949   assem_debug("movcs %s,#%d\n",regname[rt],imm);
950   u_int armval;
951   genimm_checked(imm,&armval);
952   output_w32(0x23a00000|rd_rn_rm(rt,0,0)|armval);
953 }
954
955 static void emit_cmovne_reg(int rs,int rt)
956 {
957   assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
958   output_w32(0x11a00000|rd_rn_rm(rt,0,rs));
959 }
960
961 static void emit_cmovl_reg(int rs,int rt)
962 {
963   assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
964   output_w32(0xb1a00000|rd_rn_rm(rt,0,rs));
965 }
966
967 static void emit_cmovs_reg(int rs,int rt)
968 {
969   assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
970   output_w32(0x41a00000|rd_rn_rm(rt,0,rs));
971 }
972
973 static void emit_slti32(int rs,int imm,int rt)
974 {
975   if(rs!=rt) emit_zeroreg(rt);
976   emit_cmpimm(rs,imm);
977   if(rs==rt) emit_movimm(0,rt);
978   emit_cmovl_imm(1,rt);
979 }
980
981 static void emit_sltiu32(int rs,int imm,int rt)
982 {
983   if(rs!=rt) emit_zeroreg(rt);
984   emit_cmpimm(rs,imm);
985   if(rs==rt) emit_movimm(0,rt);
986   emit_cmovb_imm(1,rt);
987 }
988
989 static void emit_cmp(int rs,int rt)
990 {
991   assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
992   output_w32(0xe1500000|rd_rn_rm(0,rs,rt));
993 }
994
995 static void emit_set_gz32(int rs, int rt)
996 {
997   //assem_debug("set_gz32\n");
998   emit_cmpimm(rs,1);
999   emit_movimm(1,rt);
1000   emit_cmovl_imm(0,rt);
1001 }
1002
1003 static void emit_set_nz32(int rs, int rt)
1004 {
1005   //assem_debug("set_nz32\n");
1006   if(rs!=rt) emit_movs(rs,rt);
1007   else emit_test(rs,rs);
1008   emit_cmovne_imm(1,rt);
1009 }
1010
1011 static void emit_set_if_less32(int rs1, int rs2, int rt)
1012 {
1013   //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1014   if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1015   emit_cmp(rs1,rs2);
1016   if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1017   emit_cmovl_imm(1,rt);
1018 }
1019
1020 static void emit_set_if_carry32(int rs1, int rs2, int rt)
1021 {
1022   //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1023   if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1024   emit_cmp(rs1,rs2);
1025   if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1026   emit_cmovb_imm(1,rt);
1027 }
1028
1029 static int can_jump_or_call(const void *a)
1030 {
1031   intptr_t offset = (u_char *)a - out - 8;
1032   return (-33554432 <= offset && offset < 33554432);
1033 }
1034
1035 static void emit_call(const void *a_)
1036 {
1037   int a = (int)a_;
1038   assem_debug("bl %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a_));
1039   u_int offset=genjmp(a);
1040   output_w32(0xeb000000|offset);
1041 }
1042
1043 static void emit_jmp(const void *a_)
1044 {
1045   int a = (int)a_;
1046   assem_debug("b %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a_));
1047   u_int offset=genjmp(a);
1048   output_w32(0xea000000|offset);
1049 }
1050
1051 static void emit_jne(const void *a_)
1052 {
1053   int a = (int)a_;
1054   assem_debug("bne %x\n",a);
1055   u_int offset=genjmp(a);
1056   output_w32(0x1a000000|offset);
1057 }
1058
1059 static void emit_jeq(const void *a_)
1060 {
1061   int a = (int)a_;
1062   assem_debug("beq %x\n",a);
1063   u_int offset=genjmp(a);
1064   output_w32(0x0a000000|offset);
1065 }
1066
1067 static void emit_js(const void *a_)
1068 {
1069   int a = (int)a_;
1070   assem_debug("bmi %x\n",a);
1071   u_int offset=genjmp(a);
1072   output_w32(0x4a000000|offset);
1073 }
1074
1075 static void emit_jns(const void *a_)
1076 {
1077   int a = (int)a_;
1078   assem_debug("bpl %x\n",a);
1079   u_int offset=genjmp(a);
1080   output_w32(0x5a000000|offset);
1081 }
1082
1083 static void emit_jl(const void *a_)
1084 {
1085   int a = (int)a_;
1086   assem_debug("blt %x\n",a);
1087   u_int offset=genjmp(a);
1088   output_w32(0xba000000|offset);
1089 }
1090
1091 static void emit_jge(const void *a_)
1092 {
1093   int a = (int)a_;
1094   assem_debug("bge %x\n",a);
1095   u_int offset=genjmp(a);
1096   output_w32(0xaa000000|offset);
1097 }
1098
1099 static void emit_jno(const void *a_)
1100 {
1101   int a = (int)a_;
1102   assem_debug("bvc %x\n",a);
1103   u_int offset=genjmp(a);
1104   output_w32(0x7a000000|offset);
1105 }
1106
1107 static void emit_jc(const void *a_)
1108 {
1109   int a = (int)a_;
1110   assem_debug("bcs %x\n",a);
1111   u_int offset=genjmp(a);
1112   output_w32(0x2a000000|offset);
1113 }
1114
1115 static void emit_jcc(const void *a_)
1116 {
1117   int a = (int)a_;
1118   assem_debug("bcc %x\n",a);
1119   u_int offset=genjmp(a);
1120   output_w32(0x3a000000|offset);
1121 }
1122
1123 static unused void emit_callreg(u_int r)
1124 {
1125   assert(r<15);
1126   assem_debug("blx %s\n",regname[r]);
1127   output_w32(0xe12fff30|r);
1128 }
1129
1130 static void emit_jmpreg(u_int r)
1131 {
1132   assem_debug("mov pc,%s\n",regname[r]);
1133   output_w32(0xe1a00000|rd_rn_rm(15,0,r));
1134 }
1135
1136 static void emit_ret(void)
1137 {
1138   emit_jmpreg(14);
1139 }
1140
1141 static void emit_readword_indexed(int offset, int rs, int rt)
1142 {
1143   assert(offset>-4096&&offset<4096);
1144   assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
1145   if(offset>=0) {
1146     output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset);
1147   }else{
1148     output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset));
1149   }
1150 }
1151
1152 static void emit_readword_dualindexedx4(int rs1, int rs2, int rt)
1153 {
1154   assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
1155   output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100);
1156 }
1157
1158 static void emit_ldrcc_dualindexed(int rs1, int rs2, int rt)
1159 {
1160   assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1161   output_w32(0x37900000|rd_rn_rm(rt,rs1,rs2));
1162 }
1163
1164 static void emit_ldrccb_dualindexed(int rs1, int rs2, int rt)
1165 {
1166   assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1167   output_w32(0x37d00000|rd_rn_rm(rt,rs1,rs2));
1168 }
1169
1170 static void emit_ldrccsb_dualindexed(int rs1, int rs2, int rt)
1171 {
1172   assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1173   output_w32(0x319000d0|rd_rn_rm(rt,rs1,rs2));
1174 }
1175
1176 static void emit_ldrcch_dualindexed(int rs1, int rs2, int rt)
1177 {
1178   assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1179   output_w32(0x319000b0|rd_rn_rm(rt,rs1,rs2));
1180 }
1181
1182 static void emit_ldrccsh_dualindexed(int rs1, int rs2, int rt)
1183 {
1184   assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1185   output_w32(0x319000f0|rd_rn_rm(rt,rs1,rs2));
1186 }
1187
1188 static void emit_movsbl_indexed(int offset, int rs, int rt)
1189 {
1190   assert(offset>-256&&offset<256);
1191   assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
1192   if(offset>=0) {
1193     output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1194   }else{
1195     output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1196   }
1197 }
1198
1199 static void emit_movswl_indexed(int offset, int rs, int rt)
1200 {
1201   assert(offset>-256&&offset<256);
1202   assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
1203   if(offset>=0) {
1204     output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1205   }else{
1206     output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1207   }
1208 }
1209
1210 static void emit_movzbl_indexed(int offset, int rs, int rt)
1211 {
1212   assert(offset>-4096&&offset<4096);
1213   assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
1214   if(offset>=0) {
1215     output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset);
1216   }else{
1217     output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset));
1218   }
1219 }
1220
1221 static void emit_movzwl_indexed(int offset, int rs, int rt)
1222 {
1223   assert(offset>-256&&offset<256);
1224   assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
1225   if(offset>=0) {
1226     output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1227   }else{
1228     output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1229   }
1230 }
1231
1232 static void emit_ldrd(int offset, int rs, int rt)
1233 {
1234   assert(offset>-256&&offset<256);
1235   assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset);
1236   if(offset>=0) {
1237     output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1238   }else{
1239     output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1240   }
1241 }
1242
1243 static void emit_readword(void *addr, int rt)
1244 {
1245   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
1246   assert(offset<4096);
1247   assem_debug("ldr %s,fp+%d\n",regname[rt],offset);
1248   output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset);
1249 }
1250
1251 static void emit_writeword_indexed(int rt, int offset, int rs)
1252 {
1253   assert(offset>-4096&&offset<4096);
1254   assem_debug("str %s,%s+%d\n",regname[rt],regname[rs],offset);
1255   if(offset>=0) {
1256     output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset);
1257   }else{
1258     output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset));
1259   }
1260 }
1261
1262 static void emit_writehword_indexed(int rt, int offset, int rs)
1263 {
1264   assert(offset>-256&&offset<256);
1265   assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset);
1266   if(offset>=0) {
1267     output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1268   }else{
1269     output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1270   }
1271 }
1272
1273 static void emit_writebyte_indexed(int rt, int offset, int rs)
1274 {
1275   assert(offset>-4096&&offset<4096);
1276   assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset);
1277   if(offset>=0) {
1278     output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset);
1279   }else{
1280     output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset));
1281   }
1282 }
1283
1284 static void emit_strcc_dualindexed(int rs1, int rs2, int rt)
1285 {
1286   assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1287   output_w32(0x37800000|rd_rn_rm(rt,rs1,rs2));
1288 }
1289
1290 static void emit_strccb_dualindexed(int rs1, int rs2, int rt)
1291 {
1292   assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1293   output_w32(0x37c00000|rd_rn_rm(rt,rs1,rs2));
1294 }
1295
1296 static void emit_strcch_dualindexed(int rs1, int rs2, int rt)
1297 {
1298   assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1299   output_w32(0x318000b0|rd_rn_rm(rt,rs1,rs2));
1300 }
1301
1302 static void emit_writeword(int rt, void *addr)
1303 {
1304   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
1305   assert(offset<4096);
1306   assem_debug("str %s,fp+%d\n",regname[rt],offset);
1307   output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset);
1308 }
1309
1310 static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
1311 {
1312   assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
1313   assert(rs1<16);
1314   assert(rs2<16);
1315   assert(hi<16);
1316   assert(lo<16);
1317   output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
1318 }
1319
1320 static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
1321 {
1322   assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
1323   assert(rs1<16);
1324   assert(rs2<16);
1325   assert(hi<16);
1326   assert(lo<16);
1327   output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
1328 }
1329
1330 static void emit_clz(int rs,int rt)
1331 {
1332   assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
1333   output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs));
1334 }
1335
1336 static void emit_subcs(int rs1,int rs2,int rt)
1337 {
1338   assem_debug("subcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1339   output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2));
1340 }
1341
1342 static void emit_shrcc_imm(int rs,u_int imm,int rt)
1343 {
1344   assert(imm>0);
1345   assert(imm<32);
1346   assem_debug("lsrcc %s,%s,#%d\n",regname[rt],regname[rs],imm);
1347   output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
1348 }
1349
1350 static void emit_shrne_imm(int rs,u_int imm,int rt)
1351 {
1352   assert(imm>0);
1353   assert(imm<32);
1354   assem_debug("lsrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
1355   output_w32(0x11a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
1356 }
1357
1358 static void emit_negmi(int rs, int rt)
1359 {
1360   assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]);
1361   output_w32(0x42600000|rd_rn_rm(rt,rs,0));
1362 }
1363
1364 static void emit_negsmi(int rs, int rt)
1365 {
1366   assem_debug("rsbsmi %s,%s,#0\n",regname[rt],regname[rs]);
1367   output_w32(0x42700000|rd_rn_rm(rt,rs,0));
1368 }
1369
1370 static void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
1371 {
1372   assem_debug("bic %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
1373   output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
1374 }
1375
1376 static void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
1377 {
1378   assem_debug("bic %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
1379   output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
1380 }
1381
1382 static void emit_teq(int rs, int rt)
1383 {
1384   assem_debug("teq %s,%s\n",regname[rs],regname[rt]);
1385   output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
1386 }
1387
1388 static unused void emit_rsbimm(int rs, int imm, int rt)
1389 {
1390   u_int armval;
1391   genimm_checked(imm,&armval);
1392   assem_debug("rsb %s,%s,#%d\n",regname[rt],regname[rs],imm);
1393   output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval);
1394 }
1395
1396 // Conditionally select one of two immediates, optimizing for small code size
1397 // This will only be called if HAVE_CMOV_IMM is defined
1398 static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
1399 {
1400   u_int armval;
1401   if(genimm(imm2-imm1,&armval)) {
1402     emit_movimm(imm1,rt);
1403     assem_debug("addne %s,%s,#%d\n",regname[rt],regname[rt],imm2-imm1);
1404     output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval);
1405   }else if(genimm(imm1-imm2,&armval)) {
1406     emit_movimm(imm1,rt);
1407     assem_debug("subne %s,%s,#%d\n",regname[rt],regname[rt],imm1-imm2);
1408     output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval);
1409   }
1410   else {
1411     #ifndef HAVE_ARMV7
1412     emit_movimm(imm1,rt);
1413     add_literal((int)out,imm2);
1414     assem_debug("ldrne %s,pc+? [=%x]\n",regname[rt],imm2);
1415     output_w32(0x15900000|rd_rn_rm(rt,15,0));
1416     #else
1417     emit_movw(imm1&0x0000FFFF,rt);
1418     if((imm1&0xFFFF)!=(imm2&0xFFFF)) {
1419       assem_debug("movwne %s,#%d (0x%x)\n",regname[rt],imm2&0xFFFF,imm2&0xFFFF);
1420       output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000));
1421     }
1422     emit_movt(imm1&0xFFFF0000,rt);
1423     if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) {
1424       assem_debug("movtne %s,#%d (0x%x)\n",regname[rt],imm2&0xffff0000,imm2&0xffff0000);
1425       output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000));
1426     }
1427     #endif
1428   }
1429 }
1430
1431 // special case for checking invalid_code
1432 static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm)
1433 {
1434   assert(imm<128&&imm>=0);
1435   assert(r>=0&&r<16);
1436   assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
1437   output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620);
1438   emit_cmpimm(HOST_TEMPREG,imm);
1439 }
1440
1441 static void emit_callne(int a)
1442 {
1443   assem_debug("blne %x\n",a);
1444   u_int offset=genjmp(a);
1445   output_w32(0x1b000000|offset);
1446 }
1447
1448 // Used to preload hash table entries
1449 static unused void emit_prefetchreg(int r)
1450 {
1451   assem_debug("pld %s\n",regname[r]);
1452   output_w32(0xf5d0f000|rd_rn_rm(0,r,0));
1453 }
1454
1455 // Special case for mini_ht
1456 static void emit_ldreq_indexed(int rs, u_int offset, int rt)
1457 {
1458   assert(offset<4096);
1459   assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset);
1460   output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset);
1461 }
1462
1463 static void emit_orrne_imm(int rs,int imm,int rt)
1464 {
1465   u_int armval;
1466   genimm_checked(imm,&armval);
1467   assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
1468   output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval);
1469 }
1470
1471 static void emit_andne_imm(int rs,int imm,int rt)
1472 {
1473   u_int armval;
1474   genimm_checked(imm,&armval);
1475   assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm);
1476   output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval);
1477 }
1478
1479 static unused void emit_addpl_imm(int rs,int imm,int rt)
1480 {
1481   u_int armval;
1482   genimm_checked(imm,&armval);
1483   assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm);
1484   output_w32(0x52800000|rd_rn_rm(rt,rs,0)|armval);
1485 }
1486
1487 static void emit_jno_unlikely(int a)
1488 {
1489   //emit_jno(a);
1490   assem_debug("addvc pc,pc,#? (%x)\n",/*a-(int)out-8,*/a);
1491   output_w32(0x72800000|rd_rn_rm(15,15,0));
1492 }
1493
1494 static void save_regs_all(u_int reglist)
1495 {
1496   int i;
1497   if(!reglist) return;
1498   assem_debug("stmia fp,{");
1499   for(i=0;i<16;i++)
1500     if(reglist&(1<<i))
1501       assem_debug("r%d,",i);
1502   assem_debug("}\n");
1503   output_w32(0xe88b0000|reglist);
1504 }
1505
1506 static void restore_regs_all(u_int reglist)
1507 {
1508   int i;
1509   if(!reglist) return;
1510   assem_debug("ldmia fp,{");
1511   for(i=0;i<16;i++)
1512     if(reglist&(1<<i))
1513       assem_debug("r%d,",i);
1514   assem_debug("}\n");
1515   output_w32(0xe89b0000|reglist);
1516 }
1517
1518 // Save registers before function call
1519 static void save_regs(u_int reglist)
1520 {
1521   reglist&=CALLER_SAVE_REGS; // only save the caller-save registers, r0-r3, r12
1522   save_regs_all(reglist);
1523 }
1524
1525 // Restore registers after function call
1526 static void restore_regs(u_int reglist)
1527 {
1528   reglist&=CALLER_SAVE_REGS;
1529   restore_regs_all(reglist);
1530 }
1531
1532 /* Stubs/epilogue */
1533
1534 static void literal_pool(int n)
1535 {
1536   if(!literalcount) return;
1537   if(n) {
1538     if((int)out-literals[0][0]<4096-n) return;
1539   }
1540   u_int *ptr;
1541   int i;
1542   for(i=0;i<literalcount;i++)
1543   {
1544     u_int l_addr=(u_int)out;
1545     int j;
1546     for(j=0;j<i;j++) {
1547       if(literals[j][1]==literals[i][1]) {
1548         //printf("dup %08x\n",literals[i][1]);
1549         l_addr=literals[j][0];
1550         break;
1551       }
1552     }
1553     ptr=(u_int *)literals[i][0];
1554     u_int offset=l_addr-(u_int)ptr-8;
1555     assert(offset<4096);
1556     assert(!(offset&3));
1557     *ptr|=offset;
1558     if(l_addr==(u_int)out) {
1559       literals[i][0]=l_addr; // remember for dupes
1560       output_w32(literals[i][1]);
1561     }
1562   }
1563   literalcount=0;
1564 }
1565
1566 static void literal_pool_jumpover(int n)
1567 {
1568   if(!literalcount) return;
1569   if(n) {
1570     if((int)out-literals[0][0]<4096-n) return;
1571   }
1572   void *jaddr = out;
1573   emit_jmp(0);
1574   literal_pool(0);
1575   set_jump_target(jaddr, out);
1576 }
1577
1578 // parsed by get_pointer, find_extjump_insn
1579 static void emit_extjump2(u_char *addr, u_int target, void *linker)
1580 {
1581   u_char *ptr=(u_char *)addr;
1582   assert((ptr[3]&0x0e)==0xa);
1583   (void)ptr;
1584
1585   emit_loadlp(target,0);
1586   emit_loadlp((u_int)addr,1);
1587   assert(addr>=ndrc->translation_cache&&addr<(ndrc->translation_cache+(1<<TARGET_SIZE_2)));
1588   //assert((target>=0x80000000&&target<0x80800000)||(target>0xA4000000&&target<0xA4001000));
1589 //DEBUG >
1590 #ifdef DEBUG_CYCLE_COUNT
1591   emit_readword(&last_count,ECX);
1592   emit_add(HOST_CCREG,ECX,HOST_CCREG);
1593   emit_readword(&next_interupt,ECX);
1594   emit_writeword(HOST_CCREG,&Count);
1595   emit_sub(HOST_CCREG,ECX,HOST_CCREG);
1596   emit_writeword(ECX,&last_count);
1597 #endif
1598 //DEBUG <
1599   emit_far_jump(linker);
1600 }
1601
1602 static void check_extjump2(void *src)
1603 {
1604   u_int *ptr = src;
1605   assert((ptr[1] & 0x0fff0000) == 0x059f0000); // ldr rx, [pc, #ofs]
1606   (void)ptr;
1607 }
1608
1609 // put rt_val into rt, potentially making use of rs with value rs_val
1610 static void emit_movimm_from(u_int rs_val,int rs,u_int rt_val,int rt)
1611 {
1612   u_int armval;
1613   int diff;
1614   if(genimm(rt_val,&armval)) {
1615     assem_debug("mov %s,#%d\n",regname[rt],rt_val);
1616     output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
1617     return;
1618   }
1619   if(genimm(~rt_val,&armval)) {
1620     assem_debug("mvn %s,#%d\n",regname[rt],rt_val);
1621     output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
1622     return;
1623   }
1624   diff=rt_val-rs_val;
1625   if(genimm(diff,&armval)) {
1626     assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],diff);
1627     output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
1628     return;
1629   }else if(genimm(-diff,&armval)) {
1630     assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-diff);
1631     output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
1632     return;
1633   }
1634   emit_movimm(rt_val,rt);
1635 }
1636
1637 // return 1 if above function can do it's job cheaply
1638 static int is_similar_value(u_int v1,u_int v2)
1639 {
1640   u_int xs;
1641   int diff;
1642   if(v1==v2) return 1;
1643   diff=v2-v1;
1644   for(xs=diff;xs!=0&&(xs&3)==0;xs>>=2)
1645     ;
1646   if(xs<0x100) return 1;
1647   for(xs=-diff;xs!=0&&(xs&3)==0;xs>>=2)
1648     ;
1649   if(xs<0x100) return 1;
1650   return 0;
1651 }
1652
1653 static void mov_loadtype_adj(enum stub_type type,int rs,int rt)
1654 {
1655   switch(type) {
1656     case LOADB_STUB:  emit_signextend8(rs,rt); break;
1657     case LOADBU_STUB: emit_andimm(rs,0xff,rt); break;
1658     case LOADH_STUB:  emit_signextend16(rs,rt); break;
1659     case LOADHU_STUB: emit_andimm(rs,0xffff,rt); break;
1660     case LOADW_STUB:  if(rs!=rt) emit_mov(rs,rt); break;
1661     default: assert(0);
1662   }
1663 }
1664
1665 #include "pcsxmem.h"
1666 #include "pcsxmem_inline.c"
1667
1668 static void do_readstub(int n)
1669 {
1670   assem_debug("do_readstub %x\n",start+stubs[n].a*4);
1671   literal_pool(256);
1672   set_jump_target(stubs[n].addr, out);
1673   enum stub_type type=stubs[n].type;
1674   int i=stubs[n].a;
1675   int rs=stubs[n].b;
1676   const struct regstat *i_regs=(struct regstat *)stubs[n].c;
1677   u_int reglist=stubs[n].e;
1678   const signed char *i_regmap=i_regs->regmap;
1679   int rt;
1680   if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) {
1681     rt=get_reg(i_regmap,FTEMP);
1682   }else{
1683     rt=get_reg(i_regmap,rt1[i]);
1684   }
1685   assert(rs>=0);
1686   int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0;
1687   void *restore_jump = NULL;
1688   reglist|=(1<<rs);
1689   for(r=0;r<=12;r++) {
1690     if(((1<<r)&0x13ff)&&((1<<r)&reglist)==0) {
1691       temp=r; break;
1692     }
1693   }
1694   if(rt>=0&&rt1[i]!=0)
1695     reglist&=~(1<<rt);
1696   if(temp==-1) {
1697     save_regs(reglist);
1698     regs_saved=1;
1699     temp=(rs==0)?2:0;
1700   }
1701   if((regs_saved||(reglist&2)==0)&&temp!=1&&rs!=1)
1702     temp2=1;
1703   emit_readword(&mem_rtab,temp);
1704   emit_shrimm(rs,12,temp2);
1705   emit_readword_dualindexedx4(temp,temp2,temp2);
1706   emit_lsls_imm(temp2,1,temp2);
1707   if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
1708     switch(type) {
1709       case LOADB_STUB:  emit_ldrccsb_dualindexed(temp2,rs,rt); break;
1710       case LOADBU_STUB: emit_ldrccb_dualindexed(temp2,rs,rt); break;
1711       case LOADH_STUB:  emit_ldrccsh_dualindexed(temp2,rs,rt); break;
1712       case LOADHU_STUB: emit_ldrcch_dualindexed(temp2,rs,rt); break;
1713       case LOADW_STUB:  emit_ldrcc_dualindexed(temp2,rs,rt); break;
1714       default: assert(0);
1715     }
1716   }
1717   if(regs_saved) {
1718     restore_jump=out;
1719     emit_jcc(0); // jump to reg restore
1720   }
1721   else
1722     emit_jcc(stubs[n].retaddr); // return address
1723
1724   if(!regs_saved)
1725     save_regs(reglist);
1726   void *handler=NULL;
1727   if(type==LOADB_STUB||type==LOADBU_STUB)
1728     handler=jump_handler_read8;
1729   if(type==LOADH_STUB||type==LOADHU_STUB)
1730     handler=jump_handler_read16;
1731   if(type==LOADW_STUB)
1732     handler=jump_handler_read32;
1733   assert(handler);
1734   pass_args(rs,temp2);
1735   int cc=get_reg(i_regmap,CCREG);
1736   if(cc<0)
1737     emit_loadreg(CCREG,2);
1738   emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n].d),2);
1739   emit_far_call(handler);
1740   if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
1741     mov_loadtype_adj(type,0,rt);
1742   }
1743   if(restore_jump)
1744     set_jump_target(restore_jump, out);
1745   restore_regs(reglist);
1746   emit_jmp(stubs[n].retaddr); // return address
1747 }
1748
1749 static void inline_readstub(enum stub_type type, int i, u_int addr,
1750   const signed char regmap[], int target, int adj, u_int reglist)
1751 {
1752   int rs=get_reg(regmap,target);
1753   int rt=get_reg(regmap,target);
1754   if(rs<0) rs=get_reg(regmap,-1);
1755   assert(rs>=0);
1756   u_int is_dynamic;
1757   uintptr_t host_addr = 0;
1758   void *handler;
1759   int cc=get_reg(regmap,CCREG);
1760   if(pcsx_direct_read(type,addr,CLOCK_ADJUST(adj),cc,target?rs:-1,rt))
1761     return;
1762   handler = get_direct_memhandler(mem_rtab, addr, type, &host_addr);
1763   if (handler == NULL) {
1764     if(rt<0||rt1[i]==0)
1765       return;
1766     if(addr!=host_addr)
1767       emit_movimm_from(addr,rs,host_addr,rs);
1768     switch(type) {
1769       case LOADB_STUB:  emit_movsbl_indexed(0,rs,rt); break;
1770       case LOADBU_STUB: emit_movzbl_indexed(0,rs,rt); break;
1771       case LOADH_STUB:  emit_movswl_indexed(0,rs,rt); break;
1772       case LOADHU_STUB: emit_movzwl_indexed(0,rs,rt); break;
1773       case LOADW_STUB:  emit_readword_indexed(0,rs,rt); break;
1774       default:          assert(0);
1775     }
1776     return;
1777   }
1778   is_dynamic=pcsxmem_is_handler_dynamic(addr);
1779   if(is_dynamic) {
1780     if(type==LOADB_STUB||type==LOADBU_STUB)
1781       handler=jump_handler_read8;
1782     if(type==LOADH_STUB||type==LOADHU_STUB)
1783       handler=jump_handler_read16;
1784     if(type==LOADW_STUB)
1785       handler=jump_handler_read32;
1786   }
1787
1788   // call a memhandler
1789   if(rt>=0&&rt1[i]!=0)
1790     reglist&=~(1<<rt);
1791   save_regs(reglist);
1792   if(target==0)
1793     emit_movimm(addr,0);
1794   else if(rs!=0)
1795     emit_mov(rs,0);
1796   if(cc<0)
1797     emit_loadreg(CCREG,2);
1798   if(is_dynamic) {
1799     emit_movimm(((u_int *)mem_rtab)[addr>>12]<<1,1);
1800     emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj),2);
1801   }
1802   else {
1803     emit_readword(&last_count,3);
1804     emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj),2);
1805     emit_add(2,3,2);
1806     emit_writeword(2,&Count);
1807   }
1808
1809   emit_far_call(handler);
1810
1811   if(rt>=0&&rt1[i]!=0) {
1812     switch(type) {
1813       case LOADB_STUB:  emit_signextend8(0,rt); break;
1814       case LOADBU_STUB: emit_andimm(0,0xff,rt); break;
1815       case LOADH_STUB:  emit_signextend16(0,rt); break;
1816       case LOADHU_STUB: emit_andimm(0,0xffff,rt); break;
1817       case LOADW_STUB:  if(rt!=0) emit_mov(0,rt); break;
1818       default:          assert(0);
1819     }
1820   }
1821   restore_regs(reglist);
1822 }
1823
1824 static void do_writestub(int n)
1825 {
1826   assem_debug("do_writestub %x\n",start+stubs[n].a*4);
1827   literal_pool(256);
1828   set_jump_target(stubs[n].addr, out);
1829   enum stub_type type=stubs[n].type;
1830   int i=stubs[n].a;
1831   int rs=stubs[n].b;
1832   const struct regstat *i_regs=(struct regstat *)stubs[n].c;
1833   u_int reglist=stubs[n].e;
1834   const signed char *i_regmap=i_regs->regmap;
1835   int rt,r;
1836   if(itype[i]==C1LS||itype[i]==C2LS) {
1837     rt=get_reg(i_regmap,r=FTEMP);
1838   }else{
1839     rt=get_reg(i_regmap,r=rs2[i]);
1840   }
1841   assert(rs>=0);
1842   assert(rt>=0);
1843   int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0;
1844   void *restore_jump = NULL;
1845   int reglist2=reglist|(1<<rs)|(1<<rt);
1846   for(rtmp=0;rtmp<=12;rtmp++) {
1847     if(((1<<rtmp)&0x13ff)&&((1<<rtmp)&reglist2)==0) {
1848       temp=rtmp; break;
1849     }
1850   }
1851   if(temp==-1) {
1852     save_regs(reglist);
1853     regs_saved=1;
1854     for(rtmp=0;rtmp<=3;rtmp++)
1855       if(rtmp!=rs&&rtmp!=rt)
1856         {temp=rtmp;break;}
1857   }
1858   if((regs_saved||(reglist2&8)==0)&&temp!=3&&rs!=3&&rt!=3)
1859     temp2=3;
1860   emit_readword(&mem_wtab,temp);
1861   emit_shrimm(rs,12,temp2);
1862   emit_readword_dualindexedx4(temp,temp2,temp2);
1863   emit_lsls_imm(temp2,1,temp2);
1864   switch(type) {
1865     case STOREB_STUB: emit_strccb_dualindexed(temp2,rs,rt); break;
1866     case STOREH_STUB: emit_strcch_dualindexed(temp2,rs,rt); break;
1867     case STOREW_STUB: emit_strcc_dualindexed(temp2,rs,rt); break;
1868     default:          assert(0);
1869   }
1870   if(regs_saved) {
1871     restore_jump=out;
1872     emit_jcc(0); // jump to reg restore
1873   }
1874   else
1875     emit_jcc(stubs[n].retaddr); // return address (invcode check)
1876
1877   if(!regs_saved)
1878     save_regs(reglist);
1879   void *handler=NULL;
1880   switch(type) {
1881     case STOREB_STUB: handler=jump_handler_write8; break;
1882     case STOREH_STUB: handler=jump_handler_write16; break;
1883     case STOREW_STUB: handler=jump_handler_write32; break;
1884     default: assert(0);
1885   }
1886   assert(handler);
1887   pass_args(rs,rt);
1888   if(temp2!=3)
1889     emit_mov(temp2,3);
1890   int cc=get_reg(i_regmap,CCREG);
1891   if(cc<0)
1892     emit_loadreg(CCREG,2);
1893   emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n].d),2);
1894   // returns new cycle_count
1895   emit_far_call(handler);
1896   emit_addimm(0,-CLOCK_ADJUST((int)stubs[n].d),cc<0?2:cc);
1897   if(cc<0)
1898     emit_storereg(CCREG,2);
1899   if(restore_jump)
1900     set_jump_target(restore_jump, out);
1901   restore_regs(reglist);
1902   emit_jmp(stubs[n].retaddr);
1903 }
1904
1905 static void inline_writestub(enum stub_type type, int i, u_int addr,
1906   const signed char regmap[], int target, int adj, u_int reglist)
1907 {
1908   int rs=get_reg(regmap,-1);
1909   int rt=get_reg(regmap,target);
1910   assert(rs>=0);
1911   assert(rt>=0);
1912   uintptr_t host_addr = 0;
1913   void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr);
1914   if (handler == NULL) {
1915     if(addr!=host_addr)
1916       emit_movimm_from(addr,rs,host_addr,rs);
1917     switch(type) {
1918       case STOREB_STUB: emit_writebyte_indexed(rt,0,rs); break;
1919       case STOREH_STUB: emit_writehword_indexed(rt,0,rs); break;
1920       case STOREW_STUB: emit_writeword_indexed(rt,0,rs); break;
1921       default:          assert(0);
1922     }
1923     return;
1924   }
1925
1926   // call a memhandler
1927   save_regs(reglist);
1928   pass_args(rs,rt);
1929   int cc=get_reg(regmap,CCREG);
1930   if(cc<0)
1931     emit_loadreg(CCREG,2);
1932   emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj),2);
1933   emit_movimm((u_int)handler,3);
1934   // returns new cycle_count
1935   emit_far_call(jump_handler_write_h);
1936   emit_addimm(0,-CLOCK_ADJUST(adj),cc<0?2:cc);
1937   if(cc<0)
1938     emit_storereg(CCREG,2);
1939   restore_regs(reglist);
1940 }
1941
1942 // this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr
1943 static void do_dirty_stub_emit_args(u_int arg0)
1944 {
1945   #ifndef HAVE_ARMV7
1946   emit_loadlp((int)source, 1);
1947   emit_loadlp((int)copy, 2);
1948   emit_loadlp(slen*4, 3);
1949   #else
1950   emit_movw(((u_int)source)&0x0000FFFF, 1);
1951   emit_movw(((u_int)copy)&0x0000FFFF, 2);
1952   emit_movt(((u_int)source)&0xFFFF0000, 1);
1953   emit_movt(((u_int)copy)&0xFFFF0000, 2);
1954   emit_movw(slen*4, 3);
1955   #endif
1956   emit_movimm(arg0, 0);
1957 }
1958
1959 static void *do_dirty_stub(int i)
1960 {
1961   assem_debug("do_dirty_stub %x\n",start+i*4);
1962   do_dirty_stub_emit_args(start + i*4);
1963   emit_far_call(verify_code);
1964   void *entry = out;
1965   load_regs_entry(i);
1966   if (entry == out)
1967     entry = instr_addr[i];
1968   emit_jmp(instr_addr[i]);
1969   return entry;
1970 }
1971
1972 static void do_dirty_stub_ds()
1973 {
1974   do_dirty_stub_emit_args(start + 1);
1975   emit_far_call(verify_code_ds);
1976 }
1977
1978 /* Special assem */
1979
1980 static void c2op_prologue(u_int op, int i, const struct regstat *i_regs, u_int reglist)
1981 {
1982   save_regs_all(reglist);
1983   cop2_call_stall_check(op, i, i_regs, 0);
1984 #ifdef PCNT
1985   emit_movimm(op, 0);
1986   emit_far_call(pcnt_gte_start);
1987 #endif
1988   emit_addimm(FP, (u_char *)&psxRegs.CP2D.r[0] - (u_char *)&dynarec_local, 0); // cop2 regs
1989 }
1990
1991 static void c2op_epilogue(u_int op,u_int reglist)
1992 {
1993 #ifdef PCNT
1994   emit_movimm(op,0);
1995   emit_far_call(pcnt_gte_end);
1996 #endif
1997   restore_regs_all(reglist);
1998 }
1999
2000 static void c2op_call_MACtoIR(int lm,int need_flags)
2001 {
2002   if(need_flags)
2003     emit_far_call(lm?gteMACtoIR_lm1:gteMACtoIR_lm0);
2004   else
2005     emit_far_call(lm?gteMACtoIR_lm1_nf:gteMACtoIR_lm0_nf);
2006 }
2007
2008 static void c2op_call_rgb_func(void *func,int lm,int need_ir,int need_flags)
2009 {
2010   emit_far_call(func);
2011   // func is C code and trashes r0
2012   emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
2013   if(need_flags||need_ir)
2014     c2op_call_MACtoIR(lm,need_flags);
2015   emit_far_call(need_flags?gteMACtoRGB:gteMACtoRGB_nf);
2016 }
2017
2018 static void c2op_assemble(int i, const struct regstat *i_regs)
2019 {
2020   u_int c2op = source[i] & 0x3f;
2021   u_int reglist_full = get_host_reglist(i_regs->regmap);
2022   u_int reglist = reglist_full & CALLER_SAVE_REGS;
2023   int need_flags, need_ir;
2024
2025   if (gte_handlers[c2op]!=NULL) {
2026     need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
2027     need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
2028     assem_debug("gte op %08x, unneeded %016llx, need_flags %d, need_ir %d\n",
2029       source[i],gte_unneeded[i+1],need_flags,need_ir);
2030     if(HACK_ENABLED(NDHACK_GTE_NO_FLAGS))
2031       need_flags=0;
2032     int shift = (source[i] >> 19) & 1;
2033     int lm = (source[i] >> 10) & 1;
2034     switch(c2op) {
2035 #ifndef DRC_DBG
2036       case GTE_MVMVA: {
2037 #ifdef HAVE_ARMV5
2038         int v  = (source[i] >> 15) & 3;
2039         int cv = (source[i] >> 13) & 3;
2040         int mx = (source[i] >> 17) & 3;
2041         reglist=reglist_full&(CALLER_SAVE_REGS|0xf0); // +{r4-r7}
2042         c2op_prologue(c2op,i,i_regs,reglist);
2043         /* r4,r5 = VXYZ(v) packed; r6 = &MX11(mx); r7 = &CV1(cv) */
2044         if(v<3)
2045           emit_ldrd(v*8,0,4);
2046         else {
2047           emit_movzwl_indexed(9*4,0,4);  // gteIR
2048           emit_movzwl_indexed(10*4,0,6);
2049           emit_movzwl_indexed(11*4,0,5);
2050           emit_orrshl_imm(6,16,4);
2051         }
2052         if(mx<3)
2053           emit_addimm(0,32*4+mx*8*4,6);
2054         else
2055           emit_readword(&zeromem_ptr,6);
2056         if(cv<3)
2057           emit_addimm(0,32*4+(cv*8+5)*4,7);
2058         else
2059           emit_readword(&zeromem_ptr,7);
2060 #ifdef __ARM_NEON__
2061         emit_movimm(source[i],1); // opcode
2062         emit_far_call(gteMVMVA_part_neon);
2063         if(need_flags) {
2064           emit_movimm(lm,1);
2065           emit_far_call(gteMACtoIR_flags_neon);
2066         }
2067 #else
2068         if(cv==3&&shift)
2069           emit_far_call((int)gteMVMVA_part_cv3sh12_arm);
2070         else {
2071           emit_movimm(shift,1);
2072           emit_far_call((int)(need_flags?gteMVMVA_part_arm:gteMVMVA_part_nf_arm));
2073         }
2074         if(need_flags||need_ir)
2075           c2op_call_MACtoIR(lm,need_flags);
2076 #endif
2077 #else /* if not HAVE_ARMV5 */
2078         c2op_prologue(c2op,i,i_regs,reglist);
2079         emit_movimm(source[i],1); // opcode
2080         emit_writeword(1,&psxRegs.code);
2081         emit_far_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
2082 #endif
2083         break;
2084       }
2085       case GTE_OP:
2086         c2op_prologue(c2op,i,i_regs,reglist);
2087         emit_far_call(shift?gteOP_part_shift:gteOP_part_noshift);
2088         if(need_flags||need_ir) {
2089           emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
2090           c2op_call_MACtoIR(lm,need_flags);
2091         }
2092         break;
2093       case GTE_DPCS:
2094         c2op_prologue(c2op,i,i_regs,reglist);
2095         c2op_call_rgb_func(shift?gteDPCS_part_shift:gteDPCS_part_noshift,lm,need_ir,need_flags);
2096         break;
2097       case GTE_INTPL:
2098         c2op_prologue(c2op,i,i_regs,reglist);
2099         c2op_call_rgb_func(shift?gteINTPL_part_shift:gteINTPL_part_noshift,lm,need_ir,need_flags);
2100         break;
2101       case GTE_SQR:
2102         c2op_prologue(c2op,i,i_regs,reglist);
2103         emit_far_call(shift?gteSQR_part_shift:gteSQR_part_noshift);
2104         if(need_flags||need_ir) {
2105           emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
2106           c2op_call_MACtoIR(lm,need_flags);
2107         }
2108         break;
2109       case GTE_DCPL:
2110         c2op_prologue(c2op,i,i_regs,reglist);
2111         c2op_call_rgb_func(gteDCPL_part,lm,need_ir,need_flags);
2112         break;
2113       case GTE_GPF:
2114         c2op_prologue(c2op,i,i_regs,reglist);
2115         c2op_call_rgb_func(shift?gteGPF_part_shift:gteGPF_part_noshift,lm,need_ir,need_flags);
2116         break;
2117       case GTE_GPL:
2118         c2op_prologue(c2op,i,i_regs,reglist);
2119         c2op_call_rgb_func(shift?gteGPL_part_shift:gteGPL_part_noshift,lm,need_ir,need_flags);
2120         break;
2121 #endif
2122       default:
2123         c2op_prologue(c2op,i,i_regs,reglist);
2124 #ifdef DRC_DBG
2125         emit_movimm(source[i],1); // opcode
2126         emit_writeword(1,&psxRegs.code);
2127 #endif
2128         emit_far_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
2129         break;
2130     }
2131     c2op_epilogue(c2op,reglist);
2132   }
2133 }
2134
2135 static void c2op_ctc2_31_assemble(signed char sl, signed char temp)
2136 {
2137   //value = value & 0x7ffff000;
2138   //if (value & 0x7f87e000) value |= 0x80000000;
2139   emit_shrimm(sl,12,temp);
2140   emit_shlimm(temp,12,temp);
2141   emit_testimm(temp,0x7f000000);
2142   emit_testeqimm(temp,0x00870000);
2143   emit_testeqimm(temp,0x0000e000);
2144   emit_orrne_imm(temp,0x80000000,temp);
2145 }
2146
2147 static void do_mfc2_31_one(u_int copr,signed char temp)
2148 {
2149   emit_readword(&reg_cop2d[copr],temp);
2150   emit_testimm(temp,0x8000); // do we need this?
2151   emit_andne_imm(temp,0,temp);
2152   emit_cmpimm(temp,0xf80);
2153   emit_andimm(temp,0xf80,temp);
2154   emit_cmovae_imm(0xf80,temp);
2155 }
2156
2157 static void c2op_mfc2_29_assemble(signed char tl, signed char temp)
2158 {
2159   if (temp < 0) {
2160     host_tempreg_acquire();
2161     temp = HOST_TEMPREG;
2162   }
2163   do_mfc2_31_one(9,temp);
2164   emit_shrimm(temp,7,tl);
2165   do_mfc2_31_one(10,temp);
2166   emit_orrshr_imm(temp,2,tl);
2167   do_mfc2_31_one(11,temp);
2168   emit_orrshl_imm(temp,3,tl);
2169   emit_writeword(tl,&reg_cop2d[29]);
2170   if (temp == HOST_TEMPREG)
2171     host_tempreg_release();
2172 }
2173
2174 static void multdiv_assemble_arm(int i,struct regstat *i_regs)
2175 {
2176   //  case 0x18: MULT
2177   //  case 0x19: MULTU
2178   //  case 0x1A: DIV
2179   //  case 0x1B: DIVU
2180   //  case 0x1C: DMULT
2181   //  case 0x1D: DMULTU
2182   //  case 0x1E: DDIV
2183   //  case 0x1F: DDIVU
2184   if(rs1[i]&&rs2[i])
2185   {
2186     if((opcode2[i]&4)==0) // 32-bit
2187     {
2188       if(opcode2[i]==0x18) // MULT
2189       {
2190         signed char m1=get_reg(i_regs->regmap,rs1[i]);
2191         signed char m2=get_reg(i_regs->regmap,rs2[i]);
2192         signed char hi=get_reg(i_regs->regmap,HIREG);
2193         signed char lo=get_reg(i_regs->regmap,LOREG);
2194         assert(m1>=0);
2195         assert(m2>=0);
2196         assert(hi>=0);
2197         assert(lo>=0);
2198         emit_smull(m1,m2,hi,lo);
2199       }
2200       if(opcode2[i]==0x19) // MULTU
2201       {
2202         signed char m1=get_reg(i_regs->regmap,rs1[i]);
2203         signed char m2=get_reg(i_regs->regmap,rs2[i]);
2204         signed char hi=get_reg(i_regs->regmap,HIREG);
2205         signed char lo=get_reg(i_regs->regmap,LOREG);
2206         assert(m1>=0);
2207         assert(m2>=0);
2208         assert(hi>=0);
2209         assert(lo>=0);
2210         emit_umull(m1,m2,hi,lo);
2211       }
2212       if(opcode2[i]==0x1A) // DIV
2213       {
2214         signed char d1=get_reg(i_regs->regmap,rs1[i]);
2215         signed char d2=get_reg(i_regs->regmap,rs2[i]);
2216         assert(d1>=0);
2217         assert(d2>=0);
2218         signed char quotient=get_reg(i_regs->regmap,LOREG);
2219         signed char remainder=get_reg(i_regs->regmap,HIREG);
2220         assert(quotient>=0);
2221         assert(remainder>=0);
2222         emit_movs(d1,remainder);
2223         emit_movimm(0xffffffff,quotient);
2224         emit_negmi(quotient,quotient); // .. quotient and ..
2225         emit_negmi(remainder,remainder); // .. remainder for div0 case (will be negated back after jump)
2226         emit_movs(d2,HOST_TEMPREG);
2227         emit_jeq(out+52); // Division by zero
2228         emit_negsmi(HOST_TEMPREG,HOST_TEMPREG);
2229 #ifdef HAVE_ARMV5
2230         emit_clz(HOST_TEMPREG,quotient);
2231         emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG);
2232 #else
2233         emit_movimm(0,quotient);
2234         emit_addpl_imm(quotient,1,quotient);
2235         emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
2236         emit_jns(out-2*4);
2237 #endif
2238         emit_orimm(quotient,1<<31,quotient);
2239         emit_shr(quotient,quotient,quotient);
2240         emit_cmp(remainder,HOST_TEMPREG);
2241         emit_subcs(remainder,HOST_TEMPREG,remainder);
2242         emit_adcs(quotient,quotient,quotient);
2243         emit_shrimm(HOST_TEMPREG,1,HOST_TEMPREG);
2244         emit_jcc(out-16); // -4
2245         emit_teq(d1,d2);
2246         emit_negmi(quotient,quotient);
2247         emit_test(d1,d1);
2248         emit_negmi(remainder,remainder);
2249       }
2250       if(opcode2[i]==0x1B) // DIVU
2251       {
2252         signed char d1=get_reg(i_regs->regmap,rs1[i]); // dividend
2253         signed char d2=get_reg(i_regs->regmap,rs2[i]); // divisor
2254         assert(d1>=0);
2255         assert(d2>=0);
2256         signed char quotient=get_reg(i_regs->regmap,LOREG);
2257         signed char remainder=get_reg(i_regs->regmap,HIREG);
2258         assert(quotient>=0);
2259         assert(remainder>=0);
2260         emit_mov(d1,remainder);
2261         emit_movimm(0xffffffff,quotient); // div0 case
2262         emit_test(d2,d2);
2263         emit_jeq(out+40); // Division by zero
2264 #ifdef HAVE_ARMV5
2265         emit_clz(d2,HOST_TEMPREG);
2266         emit_movimm(1<<31,quotient);
2267         emit_shl(d2,HOST_TEMPREG,d2);
2268 #else
2269         emit_movimm(0,HOST_TEMPREG);
2270         emit_addpl_imm(HOST_TEMPREG,1,HOST_TEMPREG);
2271         emit_lslpls_imm(d2,1,d2);
2272         emit_jns(out-2*4);
2273         emit_movimm(1<<31,quotient);
2274 #endif
2275         emit_shr(quotient,HOST_TEMPREG,quotient);
2276         emit_cmp(remainder,d2);
2277         emit_subcs(remainder,d2,remainder);
2278         emit_adcs(quotient,quotient,quotient);
2279         emit_shrcc_imm(d2,1,d2);
2280         emit_jcc(out-16); // -4
2281       }
2282     }
2283     else // 64-bit
2284       assert(0);
2285   }
2286   else
2287   {
2288     // Multiply by zero is zero.
2289     // MIPS does not have a divide by zero exception.
2290     // The result is undefined, we return zero.
2291     signed char hr=get_reg(i_regs->regmap,HIREG);
2292     signed char lr=get_reg(i_regs->regmap,LOREG);
2293     if(hr>=0) emit_zeroreg(hr);
2294     if(lr>=0) emit_zeroreg(lr);
2295   }
2296 }
2297 #define multdiv_assemble multdiv_assemble_arm
2298
2299 static void do_jump_vaddr(int rs)
2300 {
2301   emit_far_jump(jump_vaddr_reg[rs]);
2302 }
2303
2304 static void do_preload_rhash(int r) {
2305   // Don't need this for ARM.  On x86, this puts the value 0xf8 into the
2306   // register.  On ARM the hash can be done with a single instruction (below)
2307 }
2308
2309 static void do_preload_rhtbl(int ht) {
2310   emit_addimm(FP,(int)&mini_ht-(int)&dynarec_local,ht);
2311 }
2312
2313 static void do_rhash(int rs,int rh) {
2314   emit_andimm(rs,0xf8,rh);
2315 }
2316
2317 static void do_miniht_load(int ht,int rh) {
2318   assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
2319   output_w32(0xe7b00000|rd_rn_rm(rh,ht,rh));
2320 }
2321
2322 static void do_miniht_jump(int rs,int rh,int ht) {
2323   emit_cmp(rh,rs);
2324   emit_ldreq_indexed(ht,4,15);
2325   #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
2326   if(rs!=7)
2327     emit_mov(rs,7);
2328   rs=7;
2329   #endif
2330   do_jump_vaddr(rs);
2331 }
2332
2333 static void do_miniht_insert(u_int return_address,int rt,int temp) {
2334   #ifndef HAVE_ARMV7
2335   emit_movimm(return_address,rt); // PC into link register
2336   add_to_linker(out,return_address,1);
2337   emit_pcreladdr(temp);
2338   emit_writeword(rt,&mini_ht[(return_address&0xFF)>>3][0]);
2339   emit_writeword(temp,&mini_ht[(return_address&0xFF)>>3][1]);
2340   #else
2341   emit_movw(return_address&0x0000FFFF,rt);
2342   add_to_linker(out,return_address,1);
2343   emit_pcreladdr(temp);
2344   emit_writeword(temp,&mini_ht[(return_address&0xFF)>>3][1]);
2345   emit_movt(return_address&0xFFFF0000,rt);
2346   emit_writeword(rt,&mini_ht[(return_address&0xFF)>>3][0]);
2347   #endif
2348 }
2349
2350 // CPU-architecture-specific initialization
2351 static void arch_init(void)
2352 {
2353   uintptr_t diff = (u_char *)&ndrc->tramp.f - (u_char *)&ndrc->tramp.ops - 8;
2354   struct tramp_insns *ops = ndrc->tramp.ops;
2355   size_t i;
2356   assert(!(diff & 3));
2357   assert(diff < 0x1000);
2358   start_tcache_write(ops, (u_char *)ops + sizeof(ndrc->tramp.ops));
2359   for (i = 0; i < ARRAY_SIZE(ndrc->tramp.ops); i++)
2360     ops[i].ldrpc = 0xe5900000 | rd_rn_rm(15,15,0) | diff; // ldr pc, [=val]
2361   end_tcache_write(ops, (u_char *)ops + sizeof(ndrc->tramp.ops));
2362 }
2363
2364 // vim:shiftwidth=2:expandtab