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