drc: optional address error exception support
[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{
277718fa 1740 int ra = cinfo[i].addr;
1741 int rt = get_reg(regmap,target);
1742 assert(ra >= 0);
2a014d73 1743 u_int is_dynamic;
687b4580 1744 uintptr_t host_addr = 0;
643aeae3 1745 void *handler;
b1be1eee 1746 int cc=get_reg(regmap,CCREG);
277718fa 1747 if(pcsx_direct_read(type,addr,adj,cc,target?ra:-1,rt))
b1be1eee 1748 return;
643aeae3 1749 handler = get_direct_memhandler(mem_rtab, addr, type, &host_addr);
1750 if (handler == NULL) {
cf95b4f0 1751 if(rt<0||dops[i].rt1==0)
c6c3b1b3 1752 return;
13e35c04 1753 if(addr!=host_addr)
277718fa 1754 emit_movimm_from(addr,ra,host_addr,ra);
c6c3b1b3 1755 switch(type) {
277718fa 1756 case LOADB_STUB: emit_movsbl_indexed(0,ra,rt); break;
1757 case LOADBU_STUB: emit_movzbl_indexed(0,ra,rt); break;
1758 case LOADH_STUB: emit_movswl_indexed(0,ra,rt); break;
1759 case LOADHU_STUB: emit_movzwl_indexed(0,ra,rt); break;
1760 case LOADW_STUB: emit_readword_indexed(0,ra,rt); break;
c6c3b1b3 1761 default: assert(0);
1762 }
1763 return;
1764 }
b1be1eee 1765 is_dynamic=pcsxmem_is_handler_dynamic(addr);
1766 if(is_dynamic) {
1767 if(type==LOADB_STUB||type==LOADBU_STUB)
643aeae3 1768 handler=jump_handler_read8;
b1be1eee 1769 if(type==LOADH_STUB||type==LOADHU_STUB)
643aeae3 1770 handler=jump_handler_read16;
b1be1eee 1771 if(type==LOADW_STUB)
643aeae3 1772 handler=jump_handler_read32;
b1be1eee 1773 }
c6c3b1b3 1774
1775 // call a memhandler
cf95b4f0 1776 if(rt>=0&&dops[i].rt1!=0)
c6c3b1b3 1777 reglist&=~(1<<rt);
1778 save_regs(reglist);
1779 if(target==0)
1780 emit_movimm(addr,0);
277718fa 1781 else if(ra!=0)
1782 emit_mov(ra,0);
b1be1eee 1783 if(cc<0)
1784 emit_loadreg(CCREG,2);
1785 if(is_dynamic) {
1786 emit_movimm(((u_int *)mem_rtab)[addr>>12]<<1,1);
2330734f 1787 emit_addimm(cc<0?2:cc,adj,2);
c6c3b1b3 1788 }
b1be1eee 1789 else {
643aeae3 1790 emit_readword(&last_count,3);
2330734f 1791 emit_addimm(cc<0?2:cc,adj,2);
b1be1eee 1792 emit_add(2,3,2);
d7546062 1793 emit_writeword(2,&psxRegs.cycle);
b1be1eee 1794 }
1795
2a014d73 1796 emit_far_call(handler);
b1be1eee 1797
cf95b4f0 1798 if(rt>=0&&dops[i].rt1!=0) {
c6c3b1b3 1799 switch(type) {
1800 case LOADB_STUB: emit_signextend8(0,rt); break;
1801 case LOADBU_STUB: emit_andimm(0,0xff,rt); break;
1802 case LOADH_STUB: emit_signextend16(0,rt); break;
1803 case LOADHU_STUB: emit_andimm(0,0xffff,rt); break;
1804 case LOADW_STUB: if(rt!=0) emit_mov(0,rt); break;
1805 default: assert(0);
1806 }
1807 }
1808 restore_regs(reglist);
57871462 1809}
1810
e2b5e7aa 1811static void do_writestub(int n)
57871462 1812{
b14b6a8f 1813 assem_debug("do_writestub %x\n",start+stubs[n].a*4);
57871462 1814 literal_pool(256);
b14b6a8f 1815 set_jump_target(stubs[n].addr, out);
1816 enum stub_type type=stubs[n].type;
1817 int i=stubs[n].a;
1818 int rs=stubs[n].b;
81dbbf4c 1819 const struct regstat *i_regs=(struct regstat *)stubs[n].c;
b14b6a8f 1820 u_int reglist=stubs[n].e;
81dbbf4c 1821 const signed char *i_regmap=i_regs->regmap;
581335b0 1822 int rt,r;
a5cd72d0 1823 if(dops[i].itype==C2LS) {
57871462 1824 rt=get_reg(i_regmap,r=FTEMP);
1825 }else{
cf95b4f0 1826 rt=get_reg(i_regmap,r=dops[i].rs2);
57871462 1827 }
1828 assert(rs>=0);
1829 assert(rt>=0);
b14b6a8f 1830 int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0;
df4dc2b1 1831 void *restore_jump = NULL;
b96d3df7 1832 int reglist2=reglist|(1<<rs)|(1<<rt);
1833 for(rtmp=0;rtmp<=12;rtmp++) {
1834 if(((1<<rtmp)&0x13ff)&&((1<<rtmp)&reglist2)==0) {
1835 temp=rtmp; break;
1836 }
1837 }
1838 if(temp==-1) {
1839 save_regs(reglist);
1840 regs_saved=1;
1841 for(rtmp=0;rtmp<=3;rtmp++)
1842 if(rtmp!=rs&&rtmp!=rt)
1843 {temp=rtmp;break;}
1844 }
1845 if((regs_saved||(reglist2&8)==0)&&temp!=3&&rs!=3&&rt!=3)
1846 temp2=3;
643aeae3 1847 emit_readword(&mem_wtab,temp);
b96d3df7 1848 emit_shrimm(rs,12,temp2);
1849 emit_readword_dualindexedx4(temp,temp2,temp2);
1850 emit_lsls_imm(temp2,1,temp2);
1851 switch(type) {
1852 case STOREB_STUB: emit_strccb_dualindexed(temp2,rs,rt); break;
1853 case STOREH_STUB: emit_strcch_dualindexed(temp2,rs,rt); break;
1854 case STOREW_STUB: emit_strcc_dualindexed(temp2,rs,rt); break;
1855 default: assert(0);
1856 }
1857 if(regs_saved) {
df4dc2b1 1858 restore_jump=out;
b96d3df7 1859 emit_jcc(0); // jump to reg restore
1860 }
1861 else
b14b6a8f 1862 emit_jcc(stubs[n].retaddr); // return address (invcode check)
b96d3df7 1863
1864 if(!regs_saved)
1865 save_regs(reglist);
643aeae3 1866 void *handler=NULL;
b96d3df7 1867 switch(type) {
643aeae3 1868 case STOREB_STUB: handler=jump_handler_write8; break;
1869 case STOREH_STUB: handler=jump_handler_write16; break;
1870 case STOREW_STUB: handler=jump_handler_write32; break;
b14b6a8f 1871 default: assert(0);
b96d3df7 1872 }
643aeae3 1873 assert(handler);
b96d3df7 1874 pass_args(rs,rt);
1875 if(temp2!=3)
1876 emit_mov(temp2,3);
1877 int cc=get_reg(i_regmap,CCREG);
1878 if(cc<0)
1879 emit_loadreg(CCREG,2);
2330734f 1880 emit_addimm(cc<0?2:cc,(int)stubs[n].d,2);
b96d3df7 1881 // returns new cycle_count
2a014d73 1882 emit_far_call(handler);
2330734f 1883 emit_addimm(0,-(int)stubs[n].d,cc<0?2:cc);
b96d3df7 1884 if(cc<0)
1885 emit_storereg(CCREG,2);
1886 if(restore_jump)
df4dc2b1 1887 set_jump_target(restore_jump, out);
b96d3df7 1888 restore_regs(reglist);
b14b6a8f 1889 emit_jmp(stubs[n].retaddr);
57871462 1890}
1891
81dbbf4c 1892static void inline_writestub(enum stub_type type, int i, u_int addr,
1893 const signed char regmap[], int target, int adj, u_int reglist)
57871462 1894{
277718fa 1895 int ra = cinfo[i].addr;
1896 int rt = get_reg(regmap, target);
1897 assert(ra>=0);
57871462 1898 assert(rt>=0);
687b4580 1899 uintptr_t host_addr = 0;
643aeae3 1900 void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr);
1901 if (handler == NULL) {
13e35c04 1902 if(addr!=host_addr)
277718fa 1903 emit_movimm_from(addr,ra,host_addr,ra);
b96d3df7 1904 switch(type) {
277718fa 1905 case STOREB_STUB: emit_writebyte_indexed(rt,0,ra); break;
1906 case STOREH_STUB: emit_writehword_indexed(rt,0,ra); break;
1907 case STOREW_STUB: emit_writeword_indexed(rt,0,ra); break;
b96d3df7 1908 default: assert(0);
1909 }
1910 return;
1911 }
1912
1913 // call a memhandler
1914 save_regs(reglist);
277718fa 1915 pass_args(ra,rt);
b96d3df7 1916 int cc=get_reg(regmap,CCREG);
1917 if(cc<0)
1918 emit_loadreg(CCREG,2);
2330734f 1919 emit_addimm(cc<0?2:cc,adj,2);
643aeae3 1920 emit_movimm((u_int)handler,3);
b96d3df7 1921 // returns new cycle_count
2a014d73 1922 emit_far_call(jump_handler_write_h);
2330734f 1923 emit_addimm(0,-adj,cc<0?2:cc);
b96d3df7 1924 if(cc<0)
1925 emit_storereg(CCREG,2);
1926 restore_regs(reglist);
57871462 1927}
1928
57871462 1929/* Special assem */
1930
81dbbf4c 1931static void c2op_prologue(u_int op, int i, const struct regstat *i_regs, u_int reglist)
054175e9 1932{
1933 save_regs_all(reglist);
32631e6a 1934 cop2_do_stall_check(op, i, i_regs, 0);
82ed88eb 1935#ifdef PCNT
81dbbf4c 1936 emit_movimm(op, 0);
2a014d73 1937 emit_far_call(pcnt_gte_start);
82ed88eb 1938#endif
81dbbf4c 1939 emit_addimm(FP, (u_char *)&psxRegs.CP2D.r[0] - (u_char *)&dynarec_local, 0); // cop2 regs
054175e9 1940}
1941
1942static void c2op_epilogue(u_int op,u_int reglist)
1943{
82ed88eb 1944#ifdef PCNT
1945 emit_movimm(op,0);
2a014d73 1946 emit_far_call(pcnt_gte_end);
82ed88eb 1947#endif
054175e9 1948 restore_regs_all(reglist);
1949}
1950
6c0eefaf 1951static void c2op_call_MACtoIR(int lm,int need_flags)
1952{
1953 if(need_flags)
2a014d73 1954 emit_far_call(lm?gteMACtoIR_lm1:gteMACtoIR_lm0);
6c0eefaf 1955 else
2a014d73 1956 emit_far_call(lm?gteMACtoIR_lm1_nf:gteMACtoIR_lm0_nf);
6c0eefaf 1957}
1958
1959static void c2op_call_rgb_func(void *func,int lm,int need_ir,int need_flags)
1960{
2a014d73 1961 emit_far_call(func);
6c0eefaf 1962 // func is C code and trashes r0
1963 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
1964 if(need_flags||need_ir)
1965 c2op_call_MACtoIR(lm,need_flags);
2a014d73 1966 emit_far_call(need_flags?gteMACtoRGB:gteMACtoRGB_nf);
6c0eefaf 1967}
1968
81dbbf4c 1969static void c2op_assemble(int i, const struct regstat *i_regs)
b9b61529 1970{
81dbbf4c 1971 u_int c2op = source[i] & 0x3f;
1972 u_int reglist_full = get_host_reglist(i_regs->regmap);
1973 u_int reglist = reglist_full & CALLER_SAVE_REGS;
1974 int need_flags, need_ir;
b9b61529 1975
1976 if (gte_handlers[c2op]!=NULL) {
bedfea38 1977 need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
054175e9 1978 need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
cbbd8dd7 1979 assem_debug("gte op %08x, unneeded %016llx, need_flags %d, need_ir %d\n",
1980 source[i],gte_unneeded[i+1],need_flags,need_ir);
81dbbf4c 1981 if(HACK_ENABLED(NDHACK_GTE_NO_FLAGS))
0ff8c62c 1982 need_flags=0;
6c0eefaf 1983 int shift = (source[i] >> 19) & 1;
1984 int lm = (source[i] >> 10) & 1;
054175e9 1985 switch(c2op) {
19776aef 1986#ifndef DRC_DBG
054175e9 1987 case GTE_MVMVA: {
82336ba3 1988#ifdef HAVE_ARMV5
054175e9 1989 int v = (source[i] >> 15) & 3;
1990 int cv = (source[i] >> 13) & 3;
1991 int mx = (source[i] >> 17) & 3;
4d646738 1992 reglist=reglist_full&(CALLER_SAVE_REGS|0xf0); // +{r4-r7}
81dbbf4c 1993 c2op_prologue(c2op,i,i_regs,reglist);
054175e9 1994 /* r4,r5 = VXYZ(v) packed; r6 = &MX11(mx); r7 = &CV1(cv) */
1995 if(v<3)
1996 emit_ldrd(v*8,0,4);
1997 else {
1998 emit_movzwl_indexed(9*4,0,4); // gteIR
1999 emit_movzwl_indexed(10*4,0,6);
2000 emit_movzwl_indexed(11*4,0,5);
2001 emit_orrshl_imm(6,16,4);
2002 }
2003 if(mx<3)
2004 emit_addimm(0,32*4+mx*8*4,6);
2005 else
643aeae3 2006 emit_readword(&zeromem_ptr,6);
054175e9 2007 if(cv<3)
2008 emit_addimm(0,32*4+(cv*8+5)*4,7);
2009 else
643aeae3 2010 emit_readword(&zeromem_ptr,7);
054175e9 2011#ifdef __ARM_NEON__
2012 emit_movimm(source[i],1); // opcode
2a014d73 2013 emit_far_call(gteMVMVA_part_neon);
054175e9 2014 if(need_flags) {
2015 emit_movimm(lm,1);
2a014d73 2016 emit_far_call(gteMACtoIR_flags_neon);
054175e9 2017 }
2018#else
2019 if(cv==3&&shift)
33788798 2020 emit_far_call(gteMVMVA_part_cv3sh12_arm);
054175e9 2021 else {
2022 emit_movimm(shift,1);
33788798 2023 emit_far_call(need_flags?gteMVMVA_part_arm:gteMVMVA_part_nf_arm);
054175e9 2024 }
6c0eefaf 2025 if(need_flags||need_ir)
2026 c2op_call_MACtoIR(lm,need_flags);
82336ba3 2027#endif
2028#else /* if not HAVE_ARMV5 */
81dbbf4c 2029 c2op_prologue(c2op,i,i_regs,reglist);
82336ba3 2030 emit_movimm(source[i],1); // opcode
643aeae3 2031 emit_writeword(1,&psxRegs.code);
2a014d73 2032 emit_far_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
054175e9 2033#endif
2034 break;
2035 }
6c0eefaf 2036 case GTE_OP:
81dbbf4c 2037 c2op_prologue(c2op,i,i_regs,reglist);
2a014d73 2038 emit_far_call(shift?gteOP_part_shift:gteOP_part_noshift);
6c0eefaf 2039 if(need_flags||need_ir) {
2040 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
2041 c2op_call_MACtoIR(lm,need_flags);
2042 }
2043 break;
2044 case GTE_DPCS:
81dbbf4c 2045 c2op_prologue(c2op,i,i_regs,reglist);
6c0eefaf 2046 c2op_call_rgb_func(shift?gteDPCS_part_shift:gteDPCS_part_noshift,lm,need_ir,need_flags);
2047 break;
2048 case GTE_INTPL:
81dbbf4c 2049 c2op_prologue(c2op,i,i_regs,reglist);
6c0eefaf 2050 c2op_call_rgb_func(shift?gteINTPL_part_shift:gteINTPL_part_noshift,lm,need_ir,need_flags);
2051 break;
2052 case GTE_SQR:
81dbbf4c 2053 c2op_prologue(c2op,i,i_regs,reglist);
2a014d73 2054 emit_far_call(shift?gteSQR_part_shift:gteSQR_part_noshift);
6c0eefaf 2055 if(need_flags||need_ir) {
2056 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
2057 c2op_call_MACtoIR(lm,need_flags);
2058 }
2059 break;
2060 case GTE_DCPL:
81dbbf4c 2061 c2op_prologue(c2op,i,i_regs,reglist);
6c0eefaf 2062 c2op_call_rgb_func(gteDCPL_part,lm,need_ir,need_flags);
2063 break;
2064 case GTE_GPF:
81dbbf4c 2065 c2op_prologue(c2op,i,i_regs,reglist);
6c0eefaf 2066 c2op_call_rgb_func(shift?gteGPF_part_shift:gteGPF_part_noshift,lm,need_ir,need_flags);
2067 break;
2068 case GTE_GPL:
81dbbf4c 2069 c2op_prologue(c2op,i,i_regs,reglist);
6c0eefaf 2070 c2op_call_rgb_func(shift?gteGPL_part_shift:gteGPL_part_noshift,lm,need_ir,need_flags);
2071 break;
19776aef 2072#endif
054175e9 2073 default:
81dbbf4c 2074 c2op_prologue(c2op,i,i_regs,reglist);
19776aef 2075#ifdef DRC_DBG
2076 emit_movimm(source[i],1); // opcode
643aeae3 2077 emit_writeword(1,&psxRegs.code);
19776aef 2078#endif
2a014d73 2079 emit_far_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
054175e9 2080 break;
2081 }
2082 c2op_epilogue(c2op,reglist);
2083 }
b9b61529 2084}
2085
3968e69e 2086static void c2op_ctc2_31_assemble(signed char sl, signed char temp)
2087{
2088 //value = value & 0x7ffff000;
2089 //if (value & 0x7f87e000) value |= 0x80000000;
2090 emit_shrimm(sl,12,temp);
2091 emit_shlimm(temp,12,temp);
2092 emit_testimm(temp,0x7f000000);
2093 emit_testeqimm(temp,0x00870000);
2094 emit_testeqimm(temp,0x0000e000);
2095 emit_orrne_imm(temp,0x80000000,temp);
2096}
2097
2098static void do_mfc2_31_one(u_int copr,signed char temp)
2099{
2100 emit_readword(&reg_cop2d[copr],temp);
9c997d19 2101 emit_lsls_imm(temp,16,temp);
2102 emit_cmovs_imm(0,temp);
2103 emit_cmpimm(temp,0xf80<<16);
2104 emit_andimm(temp,0xf80<<16,temp);
2105 emit_cmovae_imm(0xf80<<16,temp);
3968e69e 2106}
2107
2108static void c2op_mfc2_29_assemble(signed char tl, signed char temp)
2109{
2110 if (temp < 0) {
2111 host_tempreg_acquire();
2112 temp = HOST_TEMPREG;
2113 }
2114 do_mfc2_31_one(9,temp);
9c997d19 2115 emit_shrimm(temp,7+16,tl);
3968e69e 2116 do_mfc2_31_one(10,temp);
9c997d19 2117 emit_orrshr_imm(temp,2+16,tl);
3968e69e 2118 do_mfc2_31_one(11,temp);
9c997d19 2119 emit_orrshr_imm(temp,-3+16,tl);
3968e69e 2120 emit_writeword(tl,&reg_cop2d[29]);
2121 if (temp == HOST_TEMPREG)
2122 host_tempreg_release();
2123}
2124
2330734f 2125static void multdiv_assemble_arm(int i, const struct regstat *i_regs)
57871462 2126{
2127 // case 0x18: MULT
2128 // case 0x19: MULTU
2129 // case 0x1A: DIV
2130 // case 0x1B: DIVU
cf95b4f0 2131 if(dops[i].rs1&&dops[i].rs2)
57871462 2132 {
a5cd72d0 2133 switch (dops[i].opcode2)
57871462 2134 {
a5cd72d0 2135 case 0x18: // MULT
57871462 2136 {
cf95b4f0 2137 signed char m1=get_reg(i_regs->regmap,dops[i].rs1);
2138 signed char m2=get_reg(i_regs->regmap,dops[i].rs2);
57871462 2139 signed char hi=get_reg(i_regs->regmap,HIREG);
2140 signed char lo=get_reg(i_regs->regmap,LOREG);
2141 assert(m1>=0);
2142 assert(m2>=0);
2143 assert(hi>=0);
2144 assert(lo>=0);
2145 emit_smull(m1,m2,hi,lo);
2146 }
a5cd72d0 2147 break;
2148 case 0x19: // MULTU
57871462 2149 {
cf95b4f0 2150 signed char m1=get_reg(i_regs->regmap,dops[i].rs1);
2151 signed char m2=get_reg(i_regs->regmap,dops[i].rs2);
57871462 2152 signed char hi=get_reg(i_regs->regmap,HIREG);
2153 signed char lo=get_reg(i_regs->regmap,LOREG);
2154 assert(m1>=0);
2155 assert(m2>=0);
2156 assert(hi>=0);
2157 assert(lo>=0);
2158 emit_umull(m1,m2,hi,lo);
2159 }
a5cd72d0 2160 break;
2161 case 0x1A: // DIV
57871462 2162 {
cf95b4f0 2163 signed char d1=get_reg(i_regs->regmap,dops[i].rs1);
2164 signed char d2=get_reg(i_regs->regmap,dops[i].rs2);
57871462 2165 signed char quotient=get_reg(i_regs->regmap,LOREG);
2166 signed char remainder=get_reg(i_regs->regmap,HIREG);
a5cd72d0 2167 void *jaddr_div0;
2168 assert(d1>=0);
2169 assert(d2>=0);
57871462 2170 assert(quotient>=0);
2171 assert(remainder>=0);
2172 emit_movs(d1,remainder);
44a80f6a 2173 emit_movimm(0xffffffff,quotient);
2174 emit_negmi(quotient,quotient); // .. quotient and ..
2175 emit_negmi(remainder,remainder); // .. remainder for div0 case (will be negated back after jump)
57871462 2176 emit_movs(d2,HOST_TEMPREG);
a5cd72d0 2177 jaddr_div0 = out;
2178 emit_jeq(0); // Division by zero
82336ba3 2179 emit_negsmi(HOST_TEMPREG,HOST_TEMPREG);
665f33e1 2180#ifdef HAVE_ARMV5
57871462 2181 emit_clz(HOST_TEMPREG,quotient);
a5cd72d0 2182 emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG); // shifted divisor
665f33e1 2183#else
2184 emit_movimm(0,quotient);
2185 emit_addpl_imm(quotient,1,quotient);
2186 emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
7c3a5182 2187 emit_jns(out-2*4);
665f33e1 2188#endif
57871462 2189 emit_orimm(quotient,1<<31,quotient);
2190 emit_shr(quotient,quotient,quotient);
2191 emit_cmp(remainder,HOST_TEMPREG);
2192 emit_subcs(remainder,HOST_TEMPREG,remainder);
2193 emit_adcs(quotient,quotient,quotient);
2194 emit_shrimm(HOST_TEMPREG,1,HOST_TEMPREG);
b14b6a8f 2195 emit_jcc(out-16); // -4
57871462 2196 emit_teq(d1,d2);
2197 emit_negmi(quotient,quotient);
a5cd72d0 2198 set_jump_target(jaddr_div0, out);
57871462 2199 emit_test(d1,d1);
2200 emit_negmi(remainder,remainder);
2201 }
a5cd72d0 2202 break;
2203 case 0x1B: // DIVU
57871462 2204 {
cf95b4f0 2205 signed char d1=get_reg(i_regs->regmap,dops[i].rs1); // dividend
2206 signed char d2=get_reg(i_regs->regmap,dops[i].rs2); // divisor
57871462 2207 signed char quotient=get_reg(i_regs->regmap,LOREG);
2208 signed char remainder=get_reg(i_regs->regmap,HIREG);
a5cd72d0 2209 void *jaddr_div0;
2210 assert(d1>=0);
2211 assert(d2>=0);
57871462 2212 assert(quotient>=0);
2213 assert(remainder>=0);
44a80f6a 2214 emit_mov(d1,remainder);
2215 emit_movimm(0xffffffff,quotient); // div0 case
57871462 2216 emit_test(d2,d2);
a5cd72d0 2217 jaddr_div0 = out;
2218 emit_jeq(0); // Division by zero
665f33e1 2219#ifdef HAVE_ARMV5
57871462 2220 emit_clz(d2,HOST_TEMPREG);
2221 emit_movimm(1<<31,quotient);
2222 emit_shl(d2,HOST_TEMPREG,d2);
665f33e1 2223#else
2224 emit_movimm(0,HOST_TEMPREG);
82336ba3 2225 emit_addpl_imm(HOST_TEMPREG,1,HOST_TEMPREG);
2226 emit_lslpls_imm(d2,1,d2);
7c3a5182 2227 emit_jns(out-2*4);
665f33e1 2228 emit_movimm(1<<31,quotient);
2229#endif
57871462 2230 emit_shr(quotient,HOST_TEMPREG,quotient);
2231 emit_cmp(remainder,d2);
2232 emit_subcs(remainder,d2,remainder);
2233 emit_adcs(quotient,quotient,quotient);
2234 emit_shrcc_imm(d2,1,d2);
b14b6a8f 2235 emit_jcc(out-16); // -4
a5cd72d0 2236 set_jump_target(jaddr_div0, out);
57871462 2237 }
a5cd72d0 2238 break;
57871462 2239 }
57871462 2240 }
2241 else
2242 {
57871462 2243 signed char hr=get_reg(i_regs->regmap,HIREG);
2244 signed char lr=get_reg(i_regs->regmap,LOREG);
a5cd72d0 2245 if ((dops[i].opcode2==0x1A || dops[i].opcode2==0x1B) && dops[i].rs2==0) // div 0
2246 {
2247 if (dops[i].rs1) {
2248 signed char numerator = get_reg(i_regs->regmap, dops[i].rs1);
2249 assert(numerator >= 0);
2250 if (hr < 0)
2251 hr = HOST_TEMPREG;
2252 emit_movs(numerator, hr);
2253 if (lr >= 0) {
2254 if (dops[i].opcode2 == 0x1A) { // DIV
2255 emit_movimm(0xffffffff, lr);
2256 emit_negmi(lr, lr);
2257 }
2258 else
2259 emit_movimm(~0, lr);
2260 }
2261 }
2262 else {
2263 if (hr >= 0) emit_zeroreg(hr);
2264 if (lr >= 0) emit_movimm(~0,lr);
2265 }
2266 }
2267 else if ((dops[i].opcode2==0x1A || dops[i].opcode2==0x1B) && dops[i].rs1==0)
2268 {
2269 signed char denominator = get_reg(i_regs->regmap, dops[i].rs2);
2270 assert(denominator >= 0);
2271 if (hr >= 0) emit_zeroreg(hr);
2272 if (lr >= 0) {
2273 emit_zeroreg(lr);
2274 emit_test(denominator, denominator);
2275 emit_mvneq(lr, lr);
2276 }
2277 }
2278 else
2279 {
2280 // Multiply by zero is zero.
2281 if (hr >= 0) emit_zeroreg(hr);
2282 if (lr >= 0) emit_zeroreg(lr);
2283 }
57871462 2284 }
2285}
2286#define multdiv_assemble multdiv_assemble_arm
2287
d1e4ebd9 2288static void do_jump_vaddr(int rs)
2289{
2a014d73 2290 emit_far_jump(jump_vaddr_reg[rs]);
d1e4ebd9 2291}
2292
e2b5e7aa 2293static void do_preload_rhash(int r) {
57871462 2294 // Don't need this for ARM. On x86, this puts the value 0xf8 into the
2295 // register. On ARM the hash can be done with a single instruction (below)
2296}
2297
e2b5e7aa 2298static void do_preload_rhtbl(int ht) {
57871462 2299 emit_addimm(FP,(int)&mini_ht-(int)&dynarec_local,ht);
2300}
2301
e2b5e7aa 2302static void do_rhash(int rs,int rh) {
57871462 2303 emit_andimm(rs,0xf8,rh);
2304}
2305
e2b5e7aa 2306static void do_miniht_load(int ht,int rh) {
57871462 2307 assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
2308 output_w32(0xe7b00000|rd_rn_rm(rh,ht,rh));
2309}
2310
e2b5e7aa 2311static void do_miniht_jump(int rs,int rh,int ht) {
57871462 2312 emit_cmp(rh,rs);
2313 emit_ldreq_indexed(ht,4,15);
2314 #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
d1e4ebd9 2315 if(rs!=7)
2316 emit_mov(rs,7);
2317 rs=7;
57871462 2318 #endif
d1e4ebd9 2319 do_jump_vaddr(rs);
57871462 2320}
2321
e2b5e7aa 2322static void do_miniht_insert(u_int return_address,int rt,int temp) {
665f33e1 2323 #ifndef HAVE_ARMV7
57871462 2324 emit_movimm(return_address,rt); // PC into link register
643aeae3 2325 add_to_linker(out,return_address,1);
57871462 2326 emit_pcreladdr(temp);
643aeae3 2327 emit_writeword(rt,&mini_ht[(return_address&0xFF)>>3][0]);
2328 emit_writeword(temp,&mini_ht[(return_address&0xFF)>>3][1]);
57871462 2329 #else
2330 emit_movw(return_address&0x0000FFFF,rt);
643aeae3 2331 add_to_linker(out,return_address,1);
57871462 2332 emit_pcreladdr(temp);
643aeae3 2333 emit_writeword(temp,&mini_ht[(return_address&0xFF)>>3][1]);
57871462 2334 emit_movt(return_address&0xFFFF0000,rt);
643aeae3 2335 emit_writeword(rt,&mini_ht[(return_address&0xFF)>>3][0]);
57871462 2336 #endif
2337}
2338
57871462 2339// CPU-architecture-specific initialization
2a014d73 2340static void arch_init(void)
2341{
2342 uintptr_t diff = (u_char *)&ndrc->tramp.f - (u_char *)&ndrc->tramp.ops - 8;
2343 struct tramp_insns *ops = ndrc->tramp.ops;
2344 size_t i;
2345 assert(!(diff & 3));
2346 assert(diff < 0x1000);
2347 start_tcache_write(ops, (u_char *)ops + sizeof(ndrc->tramp.ops));
2348 for (i = 0; i < ARRAY_SIZE(ndrc->tramp.ops); i++)
2349 ops[i].ldrpc = 0xe5900000 | rd_rn_rm(15,15,0) | diff; // ldr pc, [=val]
2350 end_tcache_write(ops, (u_char *)ops + sizeof(ndrc->tramp.ops));
57871462 2351}
b9b61529 2352
2353// vim:shiftwidth=2:expandtab