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