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