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