drc: starting arm64 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 *
c6c3b1b3 4 * Copyright (C) 2010-2011 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#include "../gte.h"
23#define FLAGLESS
24#include "../gte.h"
25#undef FLAGLESS
054175e9 26#include "../gte_arm.h"
27#include "../gte_neon.h"
28#include "pcnt.h"
665f33e1 29#include "arm_features.h"
054175e9 30
1e212a25 31#if defined(BASE_ADDR_FIXED)
32#elif defined(BASE_ADDR_DYNAMIC)
643aeae3 33u_char *translation_cache;
1e212a25 34#else
643aeae3 35u_char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
bdeade46 36#endif
37
4d646738 38#ifndef __MACH__
39#define CALLER_SAVE_REGS 0x100f
40#else
41#define CALLER_SAVE_REGS 0x120f
42#endif
43
e2b5e7aa 44#define unused __attribute__((unused))
45
dd114d7d 46#ifdef DRC_DBG
47#pragma GCC diagnostic ignored "-Wunused-function"
48#pragma GCC diagnostic ignored "-Wunused-variable"
49#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
50#endif
51
57871462 52extern int cycle_count;
53extern int last_count;
54extern int pcaddr;
55extern int pending_exception;
56extern int branch_target;
57extern uint64_t readmem_dword;
57871462 58extern u_int mini_ht[32][2];
57871462 59
60void indirect_jump_indexed();
61void indirect_jump();
62void do_interrupt();
63void jump_vaddr_r0();
64void jump_vaddr_r1();
65void jump_vaddr_r2();
66void jump_vaddr_r3();
67void jump_vaddr_r4();
68void jump_vaddr_r5();
69void jump_vaddr_r6();
70void jump_vaddr_r7();
71void jump_vaddr_r8();
72void jump_vaddr_r9();
73void jump_vaddr_r10();
74void jump_vaddr_r12();
75
b14b6a8f 76void * const jump_vaddr_reg[16] = {
77 jump_vaddr_r0,
78 jump_vaddr_r1,
79 jump_vaddr_r2,
80 jump_vaddr_r3,
81 jump_vaddr_r4,
82 jump_vaddr_r5,
83 jump_vaddr_r6,
84 jump_vaddr_r7,
85 jump_vaddr_r8,
86 jump_vaddr_r9,
87 jump_vaddr_r10,
57871462 88 0,
b14b6a8f 89 jump_vaddr_r12,
57871462 90 0,
91 0,
b14b6a8f 92 0
93};
57871462 94
0bbd1454 95void invalidate_addr_r0();
96void invalidate_addr_r1();
97void invalidate_addr_r2();
98void invalidate_addr_r3();
99void invalidate_addr_r4();
100void invalidate_addr_r5();
101void invalidate_addr_r6();
102void invalidate_addr_r7();
103void invalidate_addr_r8();
104void invalidate_addr_r9();
105void invalidate_addr_r10();
106void invalidate_addr_r12();
107
108const u_int invalidate_addr_reg[16] = {
109 (int)invalidate_addr_r0,
110 (int)invalidate_addr_r1,
111 (int)invalidate_addr_r2,
112 (int)invalidate_addr_r3,
113 (int)invalidate_addr_r4,
114 (int)invalidate_addr_r5,
115 (int)invalidate_addr_r6,
116 (int)invalidate_addr_r7,
117 (int)invalidate_addr_r8,
118 (int)invalidate_addr_r9,
119 (int)invalidate_addr_r10,
120 0,
121 (int)invalidate_addr_r12,
122 0,
123 0,
124 0};
125
d148d265 126static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
dd3a91a1 127
57871462 128/* Linker */
129
df4dc2b1 130static void set_jump_target(void *addr, void *target_)
57871462 131{
df4dc2b1 132 u_int target = (u_int)target_;
133 u_char *ptr = addr;
57871462 134 u_int *ptr2=(u_int *)ptr;
135 if(ptr[3]==0xe2) {
136 assert((target-(u_int)ptr2-8)<1024);
df4dc2b1 137 assert(((uintptr_t)addr&3)==0);
57871462 138 assert((target&3)==0);
139 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
df4dc2b1 140 //printf("target=%x addr=%p insn=%x\n",target,addr,*ptr2);
57871462 141 }
142 else if(ptr[3]==0x72) {
143 // generated by emit_jno_unlikely
144 if((target-(u_int)ptr2-8)<1024) {
df4dc2b1 145 assert(((uintptr_t)addr&3)==0);
57871462 146 assert((target&3)==0);
147 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
148 }
149 else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) {
df4dc2b1 150 assert(((uintptr_t)addr&3)==0);
57871462 151 assert((target&3)==0);
152 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00;
153 }
154 else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8);
155 }
156 else {
157 assert((ptr[3]&0x0e)==0xa);
158 *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
159 }
160}
161
162// This optionally copies the instruction from the target of the branch into
163// the space before the branch. Works, but the difference in speed is
164// usually insignificant.
e2b5e7aa 165#if 0
166static void set_jump_target_fillslot(int addr,u_int target,int copy)
57871462 167{
168 u_char *ptr=(u_char *)addr;
169 u_int *ptr2=(u_int *)ptr;
170 assert(!copy||ptr2[-1]==0xe28dd000);
171 if(ptr[3]==0xe2) {
172 assert(!copy);
173 assert((target-(u_int)ptr2-8)<4096);
174 *ptr2=(*ptr2&0xFFFFF000)|(target-(u_int)ptr2-8);
175 }
176 else {
177 assert((ptr[3]&0x0e)==0xa);
178 u_int target_insn=*(u_int *)target;
179 if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags
180 copy=0;
181 }
182 if((target_insn&0x0c100000)==0x04100000) { // Load
183 copy=0;
184 }
185 if(target_insn&0x08000000) {
186 copy=0;
187 }
188 if(copy) {
189 ptr2[-1]=target_insn;
190 target+=4;
191 }
192 *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
193 }
194}
e2b5e7aa 195#endif
57871462 196
197/* Literal pool */
e2b5e7aa 198static void add_literal(int addr,int val)
57871462 199{
15776b68 200 assert(literalcount<sizeof(literals)/sizeof(literals[0]));
57871462 201 literals[literalcount][0]=addr;
202 literals[literalcount][1]=val;
9f51b4b9 203 literalcount++;
204}
57871462 205
d148d265 206// from a pointer to external jump stub (which was produced by emit_extjump2)
207// find where the jumping insn is
208static void *find_extjump_insn(void *stub)
57871462 209{
210 int *ptr=(int *)(stub+4);
d148d265 211 assert((*ptr&0x0fff0000)==0x059f0000); // ldr rx, [pc, #ofs]
57871462 212 u_int offset=*ptr&0xfff;
d148d265 213 void **l_ptr=(void *)ptr+offset+8;
214 return *l_ptr;
57871462 215}
216
f968d35d 217// find where external branch is liked to using addr of it's stub:
218// get address that insn one after stub loads (dyna_linker arg1),
219// treat it as a pointer to branch insn,
220// return addr where that branch jumps to
643aeae3 221static void *get_pointer(void *stub)
57871462 222{
223 //printf("get_pointer(%x)\n",(int)stub);
d148d265 224 int *i_ptr=find_extjump_insn(stub);
57871462 225 assert((*i_ptr&0x0f000000)==0x0a000000);
643aeae3 226 return (u_char *)i_ptr+((*i_ptr<<8)>>6)+8;
57871462 227}
228
229// Find the "clean" entry point from a "dirty" entry point
230// by skipping past the call to verify_code
df4dc2b1 231static void *get_clean_addr(void *addr)
57871462 232{
df4dc2b1 233 signed int *ptr = addr;
665f33e1 234 #ifndef HAVE_ARMV7
57871462 235 ptr+=4;
236 #else
237 ptr+=6;
238 #endif
239 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
240 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
241 ptr++;
242 if((*ptr&0xFF000000)==0xea000000) {
df4dc2b1 243 return (char *)ptr+((*ptr<<8)>>6)+8; // follow jump
57871462 244 }
df4dc2b1 245 return ptr;
57871462 246}
247
e2b5e7aa 248static int verify_dirty(u_int *ptr)
57871462 249{
665f33e1 250 #ifndef HAVE_ARMV7
16c8be17 251 u_int offset;
57871462 252 // get from literal pool
15776b68 253 assert((*ptr&0xFFFF0000)==0xe59f0000);
16c8be17 254 offset=*ptr&0xfff;
255 u_int source=*(u_int*)((void *)ptr+offset+8);
256 ptr++;
257 assert((*ptr&0xFFFF0000)==0xe59f0000);
258 offset=*ptr&0xfff;
259 u_int copy=*(u_int*)((void *)ptr+offset+8);
260 ptr++;
261 assert((*ptr&0xFFFF0000)==0xe59f0000);
262 offset=*ptr&0xfff;
263 u_int len=*(u_int*)((void *)ptr+offset+8);
264 ptr++;
265 ptr++;
57871462 266 #else
267 // ARMv7 movw/movt
268 assert((*ptr&0xFFF00000)==0xe3000000);
269 u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
270 u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
271 u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
272 ptr+=6;
273 #endif
274 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
275 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
57871462 276 //printf("verify_dirty: %x %x %x\n",source,copy,len);
277 return !memcmp((void *)source,(void *)copy,len);
278}
279
280// This doesn't necessarily find all clean entry points, just
281// guarantees that it's not dirty
df4dc2b1 282static int isclean(void *addr)
57871462 283{
665f33e1 284 #ifndef HAVE_ARMV7
581335b0 285 u_int *ptr=((u_int *)addr)+4;
57871462 286 #else
581335b0 287 u_int *ptr=((u_int *)addr)+6;
57871462 288 #endif
289 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
290 if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction
291 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0;
292 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_vm) return 0;
293 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_ds) return 0;
294 return 1;
295}
296
4a35de07 297// get source that block at addr was compiled from (host pointers)
01d26796 298static void get_bounds(void *addr, u_char **start, u_char **end)
57871462 299{
643aeae3 300 u_int *ptr = addr;
665f33e1 301 #ifndef HAVE_ARMV7
16c8be17 302 u_int offset;
57871462 303 // get from literal pool
15776b68 304 assert((*ptr&0xFFFF0000)==0xe59f0000);
16c8be17 305 offset=*ptr&0xfff;
306 u_int source=*(u_int*)((void *)ptr+offset+8);
307 ptr++;
308 //assert((*ptr&0xFFFF0000)==0xe59f0000);
309 //offset=*ptr&0xfff;
310 //u_int copy=*(u_int*)((void *)ptr+offset+8);
311 ptr++;
312 assert((*ptr&0xFFFF0000)==0xe59f0000);
313 offset=*ptr&0xfff;
314 u_int len=*(u_int*)((void *)ptr+offset+8);
315 ptr++;
316 ptr++;
57871462 317 #else
318 // ARMv7 movw/movt
319 assert((*ptr&0xFFF00000)==0xe3000000);
320 u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
321 //u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
322 u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
323 ptr+=6;
324 #endif
325 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
326 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
01d26796 327 *start=(u_char *)source;
328 *end=(u_char *)source+len;
57871462 329}
330
57871462 331// Allocate a specific ARM register.
e2b5e7aa 332static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
57871462 333{
334 int n;
f776eb14 335 int dirty=0;
9f51b4b9 336
57871462 337 // see if it's already allocated (and dealloc it)
338 for(n=0;n<HOST_REGS;n++)
339 {
f776eb14 340 if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
341 dirty=(cur->dirty>>n)&1;
342 cur->regmap[n]=-1;
343 }
57871462 344 }
9f51b4b9 345
57871462 346 cur->regmap[hr]=reg;
347 cur->dirty&=~(1<<hr);
f776eb14 348 cur->dirty|=dirty<<hr;
57871462 349 cur->isconst&=~(1<<hr);
350}
351
352// Alloc cycle count into dedicated register
e2b5e7aa 353static void alloc_cc(struct regstat *cur,int i)
57871462 354{
355 alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
356}
357
57871462 358/* Assembler */
359
e2b5e7aa 360static unused char regname[16][4] = {
57871462 361 "r0",
362 "r1",
363 "r2",
364 "r3",
365 "r4",
366 "r5",
367 "r6",
368 "r7",
369 "r8",
370 "r9",
371 "r10",
372 "fp",
373 "r12",
374 "sp",
375 "lr",
376 "pc"};
377
e2b5e7aa 378static void output_w32(u_int word)
57871462 379{
380 *((u_int *)out)=word;
381 out+=4;
382}
e2b5e7aa 383
384static u_int rd_rn_rm(u_int rd, u_int rn, u_int rm)
57871462 385{
386 assert(rd<16);
387 assert(rn<16);
388 assert(rm<16);
389 return((rn<<16)|(rd<<12)|rm);
390}
e2b5e7aa 391
392static u_int rd_rn_imm_shift(u_int rd, u_int rn, u_int imm, u_int shift)
57871462 393{
394 assert(rd<16);
395 assert(rn<16);
396 assert(imm<256);
397 assert((shift&1)==0);
398 return((rn<<16)|(rd<<12)|(((32-shift)&30)<<7)|imm);
399}
e2b5e7aa 400
401static u_int genimm(u_int imm,u_int *encoded)
57871462 402{
c2e3bd42 403 *encoded=0;
404 if(imm==0) return 1;
57871462 405 int i=32;
406 while(i>0)
407 {
408 if(imm<256) {
409 *encoded=((i&30)<<7)|imm;
410 return 1;
411 }
412 imm=(imm>>2)|(imm<<30);i-=2;
413 }
414 return 0;
415}
e2b5e7aa 416
417static void genimm_checked(u_int imm,u_int *encoded)
cfbd3c6e 418{
419 u_int ret=genimm(imm,encoded);
420 assert(ret);
581335b0 421 (void)ret;
cfbd3c6e 422}
e2b5e7aa 423
424static u_int genjmp(u_int addr)
57871462 425{
426 int offset=addr-(int)out-8;
e80343e2 427 if(offset<-33554432||offset>=33554432) {
428 if (addr>2) {
c43b5311 429 SysPrintf("genjmp: out of range: %08x\n", offset);
e80343e2 430 exit(1);
431 }
432 return 0;
433 }
57871462 434 return ((u_int)offset>>2)&0xffffff;
435}
436
e2b5e7aa 437static void emit_mov(int rs,int rt)
57871462 438{
439 assem_debug("mov %s,%s\n",regname[rt],regname[rs]);
440 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs));
441}
442
e2b5e7aa 443static void emit_movs(int rs,int rt)
57871462 444{
445 assem_debug("movs %s,%s\n",regname[rt],regname[rs]);
446 output_w32(0xe1b00000|rd_rn_rm(rt,0,rs));
447}
448
e2b5e7aa 449static void emit_add(int rs1,int rs2,int rt)
57871462 450{
451 assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
452 output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2));
453}
454
e2b5e7aa 455static void emit_adds(int rs1,int rs2,int rt)
57871462 456{
457 assem_debug("adds %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
458 output_w32(0xe0900000|rd_rn_rm(rt,rs1,rs2));
459}
460
e2b5e7aa 461static void emit_adcs(int rs1,int rs2,int rt)
57871462 462{
463 assem_debug("adcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
464 output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2));
465}
466
e2b5e7aa 467static void emit_neg(int rs, int rt)
57871462 468{
469 assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
470 output_w32(0xe2600000|rd_rn_rm(rt,rs,0));
471}
472
e2b5e7aa 473static void emit_sub(int rs1,int rs2,int rt)
57871462 474{
475 assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
476 output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2));
477}
478
e2b5e7aa 479static void emit_zeroreg(int rt)
57871462 480{
481 assem_debug("mov %s,#0\n",regname[rt]);
482 output_w32(0xe3a00000|rd_rn_rm(rt,0,0));
483}
484
e2b5e7aa 485static void emit_loadlp(u_int imm,u_int rt)
790ee18e 486{
487 add_literal((int)out,imm);
488 assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
489 output_w32(0xe5900000|rd_rn_rm(rt,15,0));
490}
e2b5e7aa 491
492static void emit_movw(u_int imm,u_int rt)
790ee18e 493{
494 assert(imm<65536);
495 assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
496 output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
497}
e2b5e7aa 498
499static void emit_movt(u_int imm,u_int rt)
790ee18e 500{
501 assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
502 output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
503}
e2b5e7aa 504
505static void emit_movimm(u_int imm,u_int rt)
790ee18e 506{
507 u_int armval;
508 if(genimm(imm,&armval)) {
509 assem_debug("mov %s,#%d\n",regname[rt],imm);
510 output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
511 }else if(genimm(~imm,&armval)) {
512 assem_debug("mvn %s,#%d\n",regname[rt],imm);
513 output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
514 }else if(imm<65536) {
665f33e1 515 #ifndef HAVE_ARMV7
790ee18e 516 assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
517 output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
518 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
519 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
520 #else
521 emit_movw(imm,rt);
522 #endif
523 }else{
665f33e1 524 #ifndef HAVE_ARMV7
790ee18e 525 emit_loadlp(imm,rt);
526 #else
527 emit_movw(imm&0x0000FFFF,rt);
528 emit_movt(imm&0xFFFF0000,rt);
529 #endif
530 }
531}
e2b5e7aa 532
533static void emit_pcreladdr(u_int rt)
790ee18e 534{
535 assem_debug("add %s,pc,#?\n",regname[rt]);
536 output_w32(0xe2800000|rd_rn_rm(rt,15,0));
537}
538
e2b5e7aa 539static void emit_loadreg(int r, int hr)
57871462 540{
3d624f89 541 if(r&64) {
c43b5311 542 SysPrintf("64bit load in 32bit mode!\n");
7f2607ea 543 assert(0);
544 return;
3d624f89 545 }
57871462 546 if((r&63)==0)
547 emit_zeroreg(hr);
548 else {
3d624f89 549 int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
57871462 550 if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4);
551 if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4);
552 if(r==CCREG) addr=(int)&cycle_count;
553 if(r==CSREG) addr=(int)&Status;
57871462 554 if(r==INVCP) addr=(int)&invc_ptr;
555 u_int offset = addr-(u_int)&dynarec_local;
556 assert(offset<4096);
557 assem_debug("ldr %s,fp+%d\n",regname[hr],offset);
558 output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset);
559 }
560}
e2b5e7aa 561
562static void emit_storereg(int r, int hr)
57871462 563{
3d624f89 564 if(r&64) {
c43b5311 565 SysPrintf("64bit store in 32bit mode!\n");
7f2607ea 566 assert(0);
567 return;
3d624f89 568 }
3d624f89 569 int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
57871462 570 if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4);
571 if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4);
572 if(r==CCREG) addr=(int)&cycle_count;
57871462 573 u_int offset = addr-(u_int)&dynarec_local;
574 assert(offset<4096);
575 assem_debug("str %s,fp+%d\n",regname[hr],offset);
576 output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset);
577}
578
e2b5e7aa 579static void emit_test(int rs, int rt)
57871462 580{
581 assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
582 output_w32(0xe1100000|rd_rn_rm(0,rs,rt));
583}
584
e2b5e7aa 585static void emit_testimm(int rs,int imm)
57871462 586{
587 u_int armval;
5a05d80c 588 assem_debug("tst %s,#%d\n",regname[rs],imm);
cfbd3c6e 589 genimm_checked(imm,&armval);
57871462 590 output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval);
591}
592
e2b5e7aa 593static void emit_testeqimm(int rs,int imm)
b9b61529 594{
595 u_int armval;
596 assem_debug("tsteq %s,$%d\n",regname[rs],imm);
cfbd3c6e 597 genimm_checked(imm,&armval);
b9b61529 598 output_w32(0x03100000|rd_rn_rm(0,rs,0)|armval);
599}
600
e2b5e7aa 601static void emit_not(int rs,int rt)
57871462 602{
603 assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
604 output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
605}
606
e2b5e7aa 607static void emit_mvnmi(int rs,int rt)
b9b61529 608{
609 assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
610 output_w32(0x41e00000|rd_rn_rm(rt,0,rs));
611}
612
e2b5e7aa 613static void emit_and(u_int rs1,u_int rs2,u_int rt)
57871462 614{
615 assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
616 output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2));
617}
618
e2b5e7aa 619static void emit_or(u_int rs1,u_int rs2,u_int rt)
57871462 620{
621 assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
622 output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2));
623}
e2b5e7aa 624
e2b5e7aa 625static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
f70d384d 626{
627 assert(rs<16);
628 assert(rt<16);
629 assert(imm<32);
630 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
631 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|(imm<<7));
632}
633
e2b5e7aa 634static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
576bbd8f 635{
636 assert(rs<16);
637 assert(rt<16);
638 assert(imm<32);
639 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
640 output_w32(0xe1800020|rd_rn_rm(rt,rt,rs)|(imm<<7));
641}
642
e2b5e7aa 643static void emit_xor(u_int rs1,u_int rs2,u_int rt)
57871462 644{
645 assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
646 output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
647}
648
e2b5e7aa 649static void emit_addimm(u_int rs,int imm,u_int rt)
57871462 650{
651 assert(rs<16);
652 assert(rt<16);
653 if(imm!=0) {
57871462 654 u_int armval;
655 if(genimm(imm,&armval)) {
656 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm);
657 output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
658 }else if(genimm(-imm,&armval)) {
8a0a8423 659 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-imm);
57871462 660 output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
397614d0 661 #ifdef HAVE_ARMV7
662 }else if(rt!=rs&&(u_int)imm<65536) {
663 emit_movw(imm&0x0000ffff,rt);
664 emit_add(rs,rt,rt);
665 }else if(rt!=rs&&(u_int)-imm<65536) {
666 emit_movw(-imm&0x0000ffff,rt);
667 emit_sub(rs,rt,rt);
668 #endif
669 }else if((u_int)-imm<65536) {
57871462 670 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00);
671 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
672 output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8));
673 output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
397614d0 674 }else {
675 do {
676 int shift = (ffs(imm) - 1) & ~1;
677 int imm8 = imm & (0xff << shift);
678 genimm_checked(imm8,&armval);
679 assem_debug("add %s,%s,#0x%x\n",regname[rt],regname[rs],imm8);
680 output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
681 rs = rt;
682 imm &= ~imm8;
683 }
684 while (imm != 0);
57871462 685 }
686 }
687 else if(rs!=rt) emit_mov(rs,rt);
688}
689
e2b5e7aa 690static void emit_addimm_and_set_flags(int imm,int rt)
57871462 691{
692 assert(imm>-65536&&imm<65536);
693 u_int armval;
694 if(genimm(imm,&armval)) {
695 assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm);
696 output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval);
697 }else if(genimm(-imm,&armval)) {
698 assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],imm);
699 output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval);
700 }else if(imm<0) {
701 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF00);
702 assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
703 output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8));
704 output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
705 }else{
706 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF00);
707 assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
708 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8));
709 output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
710 }
711}
e2b5e7aa 712
713static void emit_addimm_no_flags(u_int imm,u_int rt)
57871462 714{
715 emit_addimm(rt,imm,rt);
716}
717
e2b5e7aa 718static void emit_addnop(u_int r)
57871462 719{
720 assert(r<16);
721 assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]);
722 output_w32(0xe2800000|rd_rn_rm(r,r,0));
723}
724
e2b5e7aa 725static void emit_adcimm(u_int rs,int imm,u_int rt)
57871462 726{
727 u_int armval;
cfbd3c6e 728 genimm_checked(imm,&armval);
57871462 729 assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm);
730 output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval);
731}
1edfcc68 732
e2b5e7aa 733static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl)
57871462 734{
735 // TODO: if(genimm(imm,&armval)) ...
736 // else
737 emit_movimm(imm,HOST_TEMPREG);
738 emit_adds(HOST_TEMPREG,rsl,rtl);
739 emit_adcimm(rsh,0,rth);
740}
741
e2b5e7aa 742static void emit_andimm(int rs,int imm,int rt)
57871462 743{
744 u_int armval;
790ee18e 745 if(imm==0) {
746 emit_zeroreg(rt);
747 }else if(genimm(imm,&armval)) {
57871462 748 assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm);
749 output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval);
750 }else if(genimm(~imm,&armval)) {
751 assem_debug("bic %s,%s,#%d\n",regname[rt],regname[rs],imm);
752 output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval);
753 }else if(imm==65535) {
332a4533 754 #ifndef HAVE_ARMV6
57871462 755 assem_debug("bic %s,%s,#FF000000\n",regname[rt],regname[rs]);
756 output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF);
757 assem_debug("bic %s,%s,#00FF0000\n",regname[rt],regname[rt]);
758 output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF);
759 #else
760 assem_debug("uxth %s,%s\n",regname[rt],regname[rs]);
761 output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs));
762 #endif
763 }else{
764 assert(imm>0&&imm<65535);
665f33e1 765 #ifndef HAVE_ARMV7
57871462 766 assem_debug("mov r14,#%d\n",imm&0xFF00);
767 output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8));
768 assem_debug("add r14,r14,#%d\n",imm&0xFF);
769 output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0));
770 #else
771 emit_movw(imm,HOST_TEMPREG);
772 #endif
773 assem_debug("and %s,%s,r14\n",regname[rt],regname[rs]);
774 output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG));
775 }
776}
777
e2b5e7aa 778static void emit_orimm(int rs,int imm,int rt)
57871462 779{
780 u_int armval;
790ee18e 781 if(imm==0) {
782 if(rs!=rt) emit_mov(rs,rt);
783 }else if(genimm(imm,&armval)) {
57871462 784 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm);
785 output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval);
786 }else{
787 assert(imm>0&&imm<65536);
788 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
789 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
790 output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8));
791 output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
792 }
793}
794
e2b5e7aa 795static void emit_xorimm(int rs,int imm,int rt)
57871462 796{
57871462 797 u_int armval;
790ee18e 798 if(imm==0) {
799 if(rs!=rt) emit_mov(rs,rt);
800 }else if(genimm(imm,&armval)) {
57871462 801 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm);
802 output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval);
803 }else{
514ed0d9 804 assert(imm>0&&imm<65536);
57871462 805 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
806 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
807 output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8));
808 output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
809 }
810}
811
e2b5e7aa 812static void emit_shlimm(int rs,u_int imm,int rt)
57871462 813{
814 assert(imm>0);
815 assert(imm<32);
816 //if(imm==1) ...
817 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
818 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7));
819}
820
e2b5e7aa 821static void emit_lsls_imm(int rs,int imm,int rt)
c6c3b1b3 822{
823 assert(imm>0);
824 assert(imm<32);
825 assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
826 output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
827}
828
e2b5e7aa 829static unused void emit_lslpls_imm(int rs,int imm,int rt)
665f33e1 830{
831 assert(imm>0);
832 assert(imm<32);
833 assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
834 output_w32(0x51b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
835}
836
e2b5e7aa 837static void emit_shrimm(int rs,u_int imm,int rt)
57871462 838{
839 assert(imm>0);
840 assert(imm<32);
841 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
842 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
843}
844
e2b5e7aa 845static void emit_sarimm(int rs,u_int imm,int rt)
57871462 846{
847 assert(imm>0);
848 assert(imm<32);
849 assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
850 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7));
851}
852
e2b5e7aa 853static void emit_rorimm(int rs,u_int imm,int rt)
57871462 854{
855 assert(imm>0);
856 assert(imm<32);
857 assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
858 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7));
859}
860
e2b5e7aa 861static void emit_signextend16(int rs,int rt)
b9b61529 862{
332a4533 863 #ifndef HAVE_ARMV6
b9b61529 864 emit_shlimm(rs,16,rt);
865 emit_sarimm(rt,16,rt);
866 #else
867 assem_debug("sxth %s,%s\n",regname[rt],regname[rs]);
868 output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs));
869 #endif
870}
871
e2b5e7aa 872static void emit_signextend8(int rs,int rt)
c6c3b1b3 873{
332a4533 874 #ifndef HAVE_ARMV6
c6c3b1b3 875 emit_shlimm(rs,24,rt);
876 emit_sarimm(rt,24,rt);
877 #else
878 assem_debug("sxtb %s,%s\n",regname[rt],regname[rs]);
879 output_w32(0xe6af0070|rd_rn_rm(rt,0,rs));
880 #endif
881}
882
e2b5e7aa 883static void emit_shl(u_int rs,u_int shift,u_int rt)
57871462 884{
885 assert(rs<16);
886 assert(rt<16);
887 assert(shift<16);
888 //if(imm==1) ...
889 assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
890 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8));
891}
e2b5e7aa 892
893static void emit_shr(u_int rs,u_int shift,u_int rt)
57871462 894{
895 assert(rs<16);
896 assert(rt<16);
897 assert(shift<16);
898 assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
899 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8));
900}
e2b5e7aa 901
902static void emit_sar(u_int rs,u_int shift,u_int rt)
57871462 903{
904 assert(rs<16);
905 assert(rt<16);
906 assert(shift<16);
907 assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
908 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
909}
57871462 910
e2b5e7aa 911static void emit_orrshl(u_int rs,u_int shift,u_int rt)
57871462 912{
913 assert(rs<16);
914 assert(rt<16);
915 assert(shift<16);
916 assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
917 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
918}
e2b5e7aa 919
920static void emit_orrshr(u_int rs,u_int shift,u_int rt)
57871462 921{
922 assert(rs<16);
923 assert(rt<16);
924 assert(shift<16);
925 assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
926 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8));
927}
928
e2b5e7aa 929static void emit_cmpimm(int rs,int imm)
57871462 930{
931 u_int armval;
932 if(genimm(imm,&armval)) {
5a05d80c 933 assem_debug("cmp %s,#%d\n",regname[rs],imm);
57871462 934 output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval);
935 }else if(genimm(-imm,&armval)) {
5a05d80c 936 assem_debug("cmn %s,#%d\n",regname[rs],imm);
57871462 937 output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval);
938 }else if(imm>0) {
939 assert(imm<65536);
57871462 940 emit_movimm(imm,HOST_TEMPREG);
57871462 941 assem_debug("cmp %s,r14\n",regname[rs]);
942 output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG));
943 }else{
944 assert(imm>-65536);
57871462 945 emit_movimm(-imm,HOST_TEMPREG);
57871462 946 assem_debug("cmn %s,r14\n",regname[rs]);
947 output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG));
948 }
949}
950
e2b5e7aa 951static void emit_cmovne_imm(int imm,int rt)
57871462 952{
953 assem_debug("movne %s,#%d\n",regname[rt],imm);
954 u_int armval;
cfbd3c6e 955 genimm_checked(imm,&armval);
57871462 956 output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval);
957}
e2b5e7aa 958
959static void emit_cmovl_imm(int imm,int rt)
57871462 960{
961 assem_debug("movlt %s,#%d\n",regname[rt],imm);
962 u_int armval;
cfbd3c6e 963 genimm_checked(imm,&armval);
57871462 964 output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval);
965}
e2b5e7aa 966
967static void emit_cmovb_imm(int imm,int rt)
57871462 968{
969 assem_debug("movcc %s,#%d\n",regname[rt],imm);
970 u_int armval;
cfbd3c6e 971 genimm_checked(imm,&armval);
57871462 972 output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
973}
e2b5e7aa 974
e2b5e7aa 975static void emit_cmovne_reg(int rs,int rt)
57871462 976{
977 assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
978 output_w32(0x11a00000|rd_rn_rm(rt,0,rs));
979}
e2b5e7aa 980
981static void emit_cmovl_reg(int rs,int rt)
57871462 982{
983 assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
984 output_w32(0xb1a00000|rd_rn_rm(rt,0,rs));
985}
e2b5e7aa 986
987static void emit_cmovs_reg(int rs,int rt)
57871462 988{
989 assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
990 output_w32(0x41a00000|rd_rn_rm(rt,0,rs));
991}
992
e2b5e7aa 993static void emit_slti32(int rs,int imm,int rt)
57871462 994{
995 if(rs!=rt) emit_zeroreg(rt);
996 emit_cmpimm(rs,imm);
997 if(rs==rt) emit_movimm(0,rt);
998 emit_cmovl_imm(1,rt);
999}
e2b5e7aa 1000
1001static void emit_sltiu32(int rs,int imm,int rt)
57871462 1002{
1003 if(rs!=rt) emit_zeroreg(rt);
1004 emit_cmpimm(rs,imm);
1005 if(rs==rt) emit_movimm(0,rt);
1006 emit_cmovb_imm(1,rt);
1007}
e2b5e7aa 1008
e2b5e7aa 1009static void emit_cmp(int rs,int rt)
57871462 1010{
1011 assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
1012 output_w32(0xe1500000|rd_rn_rm(0,rs,rt));
1013}
e2b5e7aa 1014
1015static void emit_set_gz32(int rs, int rt)
57871462 1016{
1017 //assem_debug("set_gz32\n");
1018 emit_cmpimm(rs,1);
1019 emit_movimm(1,rt);
1020 emit_cmovl_imm(0,rt);
1021}
e2b5e7aa 1022
1023static void emit_set_nz32(int rs, int rt)
57871462 1024{
1025 //assem_debug("set_nz32\n");
1026 if(rs!=rt) emit_movs(rs,rt);
1027 else emit_test(rs,rs);
1028 emit_cmovne_imm(1,rt);
1029}
e2b5e7aa 1030
e2b5e7aa 1031static void emit_set_if_less32(int rs1, int rs2, int rt)
57871462 1032{
1033 //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1034 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1035 emit_cmp(rs1,rs2);
1036 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1037 emit_cmovl_imm(1,rt);
1038}
e2b5e7aa 1039
1040static void emit_set_if_carry32(int rs1, int rs2, int rt)
57871462 1041{
1042 //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1043 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1044 emit_cmp(rs1,rs2);
1045 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1046 emit_cmovb_imm(1,rt);
1047}
e2b5e7aa 1048
643aeae3 1049static void emit_call(const void *a_)
57871462 1050{
643aeae3 1051 int a = (int)a_;
dd114d7d 1052 assem_debug("bl %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a));
57871462 1053 u_int offset=genjmp(a);
1054 output_w32(0xeb000000|offset);
1055}
e2b5e7aa 1056
b14b6a8f 1057static void emit_jmp(const void *a_)
57871462 1058{
b14b6a8f 1059 int a = (int)a_;
dd114d7d 1060 assem_debug("b %x (%x+%x)%s\n",a,(int)out,a-(int)out-8,func_name(a));
57871462 1061 u_int offset=genjmp(a);
1062 output_w32(0xea000000|offset);
1063}
e2b5e7aa 1064
643aeae3 1065static void emit_jne(const void *a_)
57871462 1066{
643aeae3 1067 int a = (int)a_;
57871462 1068 assem_debug("bne %x\n",a);
1069 u_int offset=genjmp(a);
1070 output_w32(0x1a000000|offset);
1071}
e2b5e7aa 1072
1073static void emit_jeq(int a)
57871462 1074{
1075 assem_debug("beq %x\n",a);
1076 u_int offset=genjmp(a);
1077 output_w32(0x0a000000|offset);
1078}
e2b5e7aa 1079
1080static void emit_js(int a)
57871462 1081{
1082 assem_debug("bmi %x\n",a);
1083 u_int offset=genjmp(a);
1084 output_w32(0x4a000000|offset);
1085}
e2b5e7aa 1086
1087static void emit_jns(int a)
57871462 1088{
1089 assem_debug("bpl %x\n",a);
1090 u_int offset=genjmp(a);
1091 output_w32(0x5a000000|offset);
1092}
e2b5e7aa 1093
1094static void emit_jl(int a)
57871462 1095{
1096 assem_debug("blt %x\n",a);
1097 u_int offset=genjmp(a);
1098 output_w32(0xba000000|offset);
1099}
e2b5e7aa 1100
1101static void emit_jge(int a)
57871462 1102{
1103 assem_debug("bge %x\n",a);
1104 u_int offset=genjmp(a);
1105 output_w32(0xaa000000|offset);
1106}
e2b5e7aa 1107
1108static void emit_jno(int a)
57871462 1109{
1110 assem_debug("bvc %x\n",a);
1111 u_int offset=genjmp(a);
1112 output_w32(0x7a000000|offset);
1113}
e2b5e7aa 1114
1115static void emit_jc(int a)
57871462 1116{
1117 assem_debug("bcs %x\n",a);
1118 u_int offset=genjmp(a);
1119 output_w32(0x2a000000|offset);
1120}
e2b5e7aa 1121
b14b6a8f 1122static void emit_jcc(void *a_)
57871462 1123{
b14b6a8f 1124 int a = (int)a_;
57871462 1125 assem_debug("bcc %x\n",a);
1126 u_int offset=genjmp(a);
1127 output_w32(0x3a000000|offset);
1128}
1129
e2b5e7aa 1130static void emit_callreg(u_int r)
57871462 1131{
c6c3b1b3 1132 assert(r<15);
1133 assem_debug("blx %s\n",regname[r]);
1134 output_w32(0xe12fff30|r);
57871462 1135}
e2b5e7aa 1136
1137static void emit_jmpreg(u_int r)
57871462 1138{
1139 assem_debug("mov pc,%s\n",regname[r]);
1140 output_w32(0xe1a00000|rd_rn_rm(15,0,r));
1141}
1142
be516ebe 1143static void emit_ret(void)
1144{
1145 emit_jmpreg(14);
1146}
1147
e2b5e7aa 1148static void emit_readword_indexed(int offset, int rs, int rt)
57871462 1149{
1150 assert(offset>-4096&&offset<4096);
1151 assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
1152 if(offset>=0) {
1153 output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset);
1154 }else{
1155 output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset));
1156 }
1157}
e2b5e7aa 1158
1159static void emit_readword_dualindexedx4(int rs1, int rs2, int rt)
57871462 1160{
1161 assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
1162 output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100);
1163}
e2b5e7aa 1164
1165static void emit_ldrcc_dualindexed(int rs1, int rs2, int rt)
c6c3b1b3 1166{
1167 assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1168 output_w32(0x37900000|rd_rn_rm(rt,rs1,rs2));
1169}
e2b5e7aa 1170
1171static void emit_ldrccb_dualindexed(int rs1, int rs2, int rt)
c6c3b1b3 1172{
1173 assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1174 output_w32(0x37d00000|rd_rn_rm(rt,rs1,rs2));
1175}
e2b5e7aa 1176
1177static void emit_ldrccsb_dualindexed(int rs1, int rs2, int rt)
c6c3b1b3 1178{
1179 assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1180 output_w32(0x319000d0|rd_rn_rm(rt,rs1,rs2));
1181}
e2b5e7aa 1182
1183static void emit_ldrcch_dualindexed(int rs1, int rs2, int rt)
c6c3b1b3 1184{
1185 assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1186 output_w32(0x319000b0|rd_rn_rm(rt,rs1,rs2));
1187}
e2b5e7aa 1188
1189static void emit_ldrccsh_dualindexed(int rs1, int rs2, int rt)
c6c3b1b3 1190{
1191 assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1192 output_w32(0x319000f0|rd_rn_rm(rt,rs1,rs2));
1193}
e2b5e7aa 1194
e2b5e7aa 1195static void emit_movsbl_indexed(int offset, int rs, int rt)
57871462 1196{
1197 assert(offset>-256&&offset<256);
1198 assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
1199 if(offset>=0) {
1200 output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1201 }else{
1202 output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1203 }
1204}
e2b5e7aa 1205
e2b5e7aa 1206static void emit_movswl_indexed(int offset, int rs, int rt)
57871462 1207{
1208 assert(offset>-256&&offset<256);
1209 assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
1210 if(offset>=0) {
1211 output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1212 }else{
1213 output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1214 }
1215}
e2b5e7aa 1216
1217static void emit_movzbl_indexed(int offset, int rs, int rt)
57871462 1218{
1219 assert(offset>-4096&&offset<4096);
1220 assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
1221 if(offset>=0) {
1222 output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset);
1223 }else{
1224 output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset));
1225 }
1226}
e2b5e7aa 1227
e2b5e7aa 1228static void emit_movzwl_indexed(int offset, int rs, int rt)
57871462 1229{
1230 assert(offset>-256&&offset<256);
1231 assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
1232 if(offset>=0) {
1233 output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1234 }else{
1235 output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1236 }
1237}
e2b5e7aa 1238
054175e9 1239static void emit_ldrd(int offset, int rs, int rt)
1240{
1241 assert(offset>-256&&offset<256);
1242 assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset);
1243 if(offset>=0) {
1244 output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1245 }else{
1246 output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1247 }
1248}
e2b5e7aa 1249
643aeae3 1250static void emit_readword(void *addr, int rt)
57871462 1251{
643aeae3 1252 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
57871462 1253 assert(offset<4096);
1254 assem_debug("ldr %s,fp+%d\n",regname[rt],offset);
1255 output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset);
1256}
e2b5e7aa 1257
e2b5e7aa 1258static void emit_writeword_indexed(int rt, int offset, int rs)
57871462 1259{
1260 assert(offset>-4096&&offset<4096);
1261 assem_debug("str %s,%s+%d\n",regname[rt],regname[rs],offset);
1262 if(offset>=0) {
1263 output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset);
1264 }else{
1265 output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset));
1266 }
1267}
e2b5e7aa 1268
e2b5e7aa 1269static void emit_writehword_indexed(int rt, int offset, int rs)
57871462 1270{
1271 assert(offset>-256&&offset<256);
1272 assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset);
1273 if(offset>=0) {
1274 output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1275 }else{
1276 output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1277 }
1278}
e2b5e7aa 1279
1280static void emit_writebyte_indexed(int rt, int offset, int rs)
57871462 1281{
1282 assert(offset>-4096&&offset<4096);
1283 assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset);
1284 if(offset>=0) {
1285 output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset);
1286 }else{
1287 output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset));
1288 }
1289}
e2b5e7aa 1290
e2b5e7aa 1291static void emit_strcc_dualindexed(int rs1, int rs2, int rt)
b96d3df7 1292{
1293 assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1294 output_w32(0x37800000|rd_rn_rm(rt,rs1,rs2));
1295}
e2b5e7aa 1296
1297static void emit_strccb_dualindexed(int rs1, int rs2, int rt)
b96d3df7 1298{
1299 assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1300 output_w32(0x37c00000|rd_rn_rm(rt,rs1,rs2));
1301}
e2b5e7aa 1302
1303static void emit_strcch_dualindexed(int rs1, int rs2, int rt)
b96d3df7 1304{
1305 assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1306 output_w32(0x318000b0|rd_rn_rm(rt,rs1,rs2));
1307}
e2b5e7aa 1308
643aeae3 1309static void emit_writeword(int rt, void *addr)
57871462 1310{
643aeae3 1311 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
57871462 1312 assert(offset<4096);
1313 assem_debug("str %s,fp+%d\n",regname[rt],offset);
1314 output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset);
1315}
e2b5e7aa 1316
e2b5e7aa 1317static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
57871462 1318{
1319 assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
1320 assert(rs1<16);
1321 assert(rs2<16);
1322 assert(hi<16);
1323 assert(lo<16);
1324 output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
1325}
e2b5e7aa 1326
1327static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
57871462 1328{
1329 assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
1330 assert(rs1<16);
1331 assert(rs2<16);
1332 assert(hi<16);
1333 assert(lo<16);
1334 output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
1335}
1336
e2b5e7aa 1337static void emit_clz(int rs,int rt)
57871462 1338{
1339 assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
1340 output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs));
1341}
1342
e2b5e7aa 1343static void emit_subcs(int rs1,int rs2,int rt)
57871462 1344{
1345 assem_debug("subcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1346 output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2));
1347}
1348
e2b5e7aa 1349static void emit_shrcc_imm(int rs,u_int imm,int rt)
57871462 1350{
1351 assert(imm>0);
1352 assert(imm<32);
1353 assem_debug("lsrcc %s,%s,#%d\n",regname[rt],regname[rs],imm);
1354 output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
1355}
1356
e2b5e7aa 1357static void emit_shrne_imm(int rs,u_int imm,int rt)
b1be1eee 1358{
1359 assert(imm>0);
1360 assert(imm<32);
1361 assem_debug("lsrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
1362 output_w32(0x11a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
1363}
1364
e2b5e7aa 1365static void emit_negmi(int rs, int rt)
57871462 1366{
1367 assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]);
1368 output_w32(0x42600000|rd_rn_rm(rt,rs,0));
1369}
1370
e2b5e7aa 1371static void emit_negsmi(int rs, int rt)
57871462 1372{
1373 assem_debug("rsbsmi %s,%s,#0\n",regname[rt],regname[rs]);
1374 output_w32(0x42700000|rd_rn_rm(rt,rs,0));
1375}
1376
e2b5e7aa 1377static void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
57871462 1378{
1379 assem_debug("bic %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
1380 output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
1381}
1382
e2b5e7aa 1383static void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
57871462 1384{
1385 assem_debug("bic %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
1386 output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
1387}
1388
e2b5e7aa 1389static void emit_teq(int rs, int rt)
57871462 1390{
1391 assem_debug("teq %s,%s\n",regname[rs],regname[rt]);
1392 output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
1393}
1394
e2b5e7aa 1395static void emit_rsbimm(int rs, int imm, int rt)
57871462 1396{
1397 u_int armval;
cfbd3c6e 1398 genimm_checked(imm,&armval);
57871462 1399 assem_debug("rsb %s,%s,#%d\n",regname[rt],regname[rs],imm);
1400 output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval);
1401}
1402
1403// Load 2 immediates optimizing for small code size
e2b5e7aa 1404static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
57871462 1405{
1406 emit_movimm(imm1,rt1);
1407 u_int armval;
1408 if(genimm(imm2-imm1,&armval)) {
1409 assem_debug("add %s,%s,#%d\n",regname[rt2],regname[rt1],imm2-imm1);
1410 output_w32(0xe2800000|rd_rn_rm(rt2,rt1,0)|armval);
1411 }else if(genimm(imm1-imm2,&armval)) {
1412 assem_debug("sub %s,%s,#%d\n",regname[rt2],regname[rt1],imm1-imm2);
1413 output_w32(0xe2400000|rd_rn_rm(rt2,rt1,0)|armval);
1414 }
1415 else emit_movimm(imm2,rt2);
1416}
1417
1418// Conditionally select one of two immediates, optimizing for small code size
1419// This will only be called if HAVE_CMOV_IMM is defined
e2b5e7aa 1420static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
57871462 1421{
1422 u_int armval;
1423 if(genimm(imm2-imm1,&armval)) {
1424 emit_movimm(imm1,rt);
1425 assem_debug("addne %s,%s,#%d\n",regname[rt],regname[rt],imm2-imm1);
1426 output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval);
1427 }else if(genimm(imm1-imm2,&armval)) {
1428 emit_movimm(imm1,rt);
1429 assem_debug("subne %s,%s,#%d\n",regname[rt],regname[rt],imm1-imm2);
1430 output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval);
1431 }
1432 else {
665f33e1 1433 #ifndef HAVE_ARMV7
57871462 1434 emit_movimm(imm1,rt);
1435 add_literal((int)out,imm2);
1436 assem_debug("ldrne %s,pc+? [=%x]\n",regname[rt],imm2);
1437 output_w32(0x15900000|rd_rn_rm(rt,15,0));
1438 #else
1439 emit_movw(imm1&0x0000FFFF,rt);
1440 if((imm1&0xFFFF)!=(imm2&0xFFFF)) {
1441 assem_debug("movwne %s,#%d (0x%x)\n",regname[rt],imm2&0xFFFF,imm2&0xFFFF);
1442 output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000));
1443 }
1444 emit_movt(imm1&0xFFFF0000,rt);
1445 if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) {
1446 assem_debug("movtne %s,#%d (0x%x)\n",regname[rt],imm2&0xffff0000,imm2&0xffff0000);
1447 output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000));
1448 }
1449 #endif
1450 }
1451}
1452
57871462 1453// special case for checking invalid_code
e2b5e7aa 1454static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm)
57871462 1455{
1456 assert(imm<128&&imm>=0);
1457 assert(r>=0&&r<16);
1458 assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
1459 output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620);
1460 emit_cmpimm(HOST_TEMPREG,imm);
1461}
1462
e2b5e7aa 1463static void emit_callne(int a)
0bbd1454 1464{
1465 assem_debug("blne %x\n",a);
1466 u_int offset=genjmp(a);
1467 output_w32(0x1b000000|offset);
1468}
1469
57871462 1470// Used to preload hash table entries
e2b5e7aa 1471static unused void emit_prefetchreg(int r)
57871462 1472{
1473 assem_debug("pld %s\n",regname[r]);
1474 output_w32(0xf5d0f000|rd_rn_rm(0,r,0));
1475}
1476
1477// Special case for mini_ht
e2b5e7aa 1478static void emit_ldreq_indexed(int rs, u_int offset, int rt)
57871462 1479{
1480 assert(offset<4096);
1481 assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset);
1482 output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset);
1483}
1484
e2b5e7aa 1485static void emit_orrne_imm(int rs,int imm,int rt)
b9b61529 1486{
1487 u_int armval;
cfbd3c6e 1488 genimm_checked(imm,&armval);
b9b61529 1489 assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
1490 output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval);
1491}
1492
e2b5e7aa 1493static void emit_andne_imm(int rs,int imm,int rt)
b9b61529 1494{
1495 u_int armval;
cfbd3c6e 1496 genimm_checked(imm,&armval);
b9b61529 1497 assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm);
1498 output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval);
1499}
1500
e2b5e7aa 1501static unused void emit_addpl_imm(int rs,int imm,int rt)
665f33e1 1502{
1503 u_int armval;
1504 genimm_checked(imm,&armval);
1505 assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm);
1506 output_w32(0x52800000|rd_rn_rm(rt,rs,0)|armval);
1507}
1508
e2b5e7aa 1509static void emit_jno_unlikely(int a)
57871462 1510{
1511 //emit_jno(a);
1512 assem_debug("addvc pc,pc,#? (%x)\n",/*a-(int)out-8,*/a);
1513 output_w32(0x72800000|rd_rn_rm(15,15,0));
1514}
1515
054175e9 1516static void save_regs_all(u_int reglist)
57871462 1517{
054175e9 1518 int i;
57871462 1519 if(!reglist) return;
1520 assem_debug("stmia fp,{");
054175e9 1521 for(i=0;i<16;i++)
1522 if(reglist&(1<<i))
1523 assem_debug("r%d,",i);
57871462 1524 assem_debug("}\n");
1525 output_w32(0xe88b0000|reglist);
1526}
e2b5e7aa 1527
054175e9 1528static void restore_regs_all(u_int reglist)
57871462 1529{
054175e9 1530 int i;
57871462 1531 if(!reglist) return;
1532 assem_debug("ldmia fp,{");