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