fix clang warnings
[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
054175e9 22#ifdef PCSX
6c0eefaf 23#include "../gte.h"
24#define FLAGLESS
25#include "../gte.h"
26#undef FLAGLESS
054175e9 27#include "../gte_arm.h"
28#include "../gte_neon.h"
29#include "pcnt.h"
30#endif
665f33e1 31#include "arm_features.h"
054175e9 32
a327ad27 33#if !BASE_ADDR_FIXED
bdeade46 34char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
35#endif
36
57871462 37extern int cycle_count;
38extern int last_count;
39extern int pcaddr;
40extern int pending_exception;
41extern int branch_target;
42extern uint64_t readmem_dword;
3d624f89 43#ifdef MUPEN64
57871462 44extern precomp_instr fake_pc;
3d624f89 45#endif
57871462 46extern void *dynarec_local;
47extern u_int memory_map[1048576];
48extern u_int mini_ht[32][2];
49extern u_int rounding_modes[4];
50
51void indirect_jump_indexed();
52void indirect_jump();
53void do_interrupt();
54void jump_vaddr_r0();
55void jump_vaddr_r1();
56void jump_vaddr_r2();
57void jump_vaddr_r3();
58void jump_vaddr_r4();
59void jump_vaddr_r5();
60void jump_vaddr_r6();
61void jump_vaddr_r7();
62void jump_vaddr_r8();
63void jump_vaddr_r9();
64void jump_vaddr_r10();
65void jump_vaddr_r12();
66
67const u_int jump_vaddr_reg[16] = {
68 (int)jump_vaddr_r0,
69 (int)jump_vaddr_r1,
70 (int)jump_vaddr_r2,
71 (int)jump_vaddr_r3,
72 (int)jump_vaddr_r4,
73 (int)jump_vaddr_r5,
74 (int)jump_vaddr_r6,
75 (int)jump_vaddr_r7,
76 (int)jump_vaddr_r8,
77 (int)jump_vaddr_r9,
78 (int)jump_vaddr_r10,
79 0,
80 (int)jump_vaddr_r12,
81 0,
82 0,
83 0};
84
0bbd1454 85void invalidate_addr_r0();
86void invalidate_addr_r1();
87void invalidate_addr_r2();
88void invalidate_addr_r3();
89void invalidate_addr_r4();
90void invalidate_addr_r5();
91void invalidate_addr_r6();
92void invalidate_addr_r7();
93void invalidate_addr_r8();
94void invalidate_addr_r9();
95void invalidate_addr_r10();
96void invalidate_addr_r12();
97
98const u_int invalidate_addr_reg[16] = {
99 (int)invalidate_addr_r0,
100 (int)invalidate_addr_r1,
101 (int)invalidate_addr_r2,
102 (int)invalidate_addr_r3,
103 (int)invalidate_addr_r4,
104 (int)invalidate_addr_r5,
105 (int)invalidate_addr_r6,
106 (int)invalidate_addr_r7,
107 (int)invalidate_addr_r8,
108 (int)invalidate_addr_r9,
109 (int)invalidate_addr_r10,
110 0,
111 (int)invalidate_addr_r12,
112 0,
113 0,
114 0};
115
57871462 116#include "fpu.h"
117
dd3a91a1 118unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
119
57871462 120/* Linker */
121
122void set_jump_target(int addr,u_int target)
123{
124 u_char *ptr=(u_char *)addr;
125 u_int *ptr2=(u_int *)ptr;
126 if(ptr[3]==0xe2) {
127 assert((target-(u_int)ptr2-8)<1024);
128 assert((addr&3)==0);
129 assert((target&3)==0);
130 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
131 //printf("target=%x addr=%x insn=%x\n",target,addr,*ptr2);
132 }
133 else if(ptr[3]==0x72) {
134 // generated by emit_jno_unlikely
135 if((target-(u_int)ptr2-8)<1024) {
136 assert((addr&3)==0);
137 assert((target&3)==0);
138 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
139 }
140 else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) {
141 assert((addr&3)==0);
142 assert((target&3)==0);
143 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00;
144 }
145 else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8);
146 }
147 else {
148 assert((ptr[3]&0x0e)==0xa);
149 *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
150 }
151}
152
153// This optionally copies the instruction from the target of the branch into
154// the space before the branch. Works, but the difference in speed is
155// usually insignificant.
156void set_jump_target_fillslot(int addr,u_int target,int copy)
157{
158 u_char *ptr=(u_char *)addr;
159 u_int *ptr2=(u_int *)ptr;
160 assert(!copy||ptr2[-1]==0xe28dd000);
161 if(ptr[3]==0xe2) {
162 assert(!copy);
163 assert((target-(u_int)ptr2-8)<4096);
164 *ptr2=(*ptr2&0xFFFFF000)|(target-(u_int)ptr2-8);
165 }
166 else {
167 assert((ptr[3]&0x0e)==0xa);
168 u_int target_insn=*(u_int *)target;
169 if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags
170 copy=0;
171 }
172 if((target_insn&0x0c100000)==0x04100000) { // Load
173 copy=0;
174 }
175 if(target_insn&0x08000000) {
176 copy=0;
177 }
178 if(copy) {
179 ptr2[-1]=target_insn;
180 target+=4;
181 }
182 *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
183 }
184}
185
186/* Literal pool */
187add_literal(int addr,int val)
188{
15776b68 189 assert(literalcount<sizeof(literals)/sizeof(literals[0]));
57871462 190 literals[literalcount][0]=addr;
191 literals[literalcount][1]=val;
192 literalcount++;
193}
194
f76eeef9 195void *kill_pointer(void *stub)
57871462 196{
197 int *ptr=(int *)(stub+4);
198 assert((*ptr&0x0ff00000)==0x05900000);
199 u_int offset=*ptr&0xfff;
200 int **l_ptr=(void *)ptr+offset+8;
201 int *i_ptr=*l_ptr;
202 set_jump_target((int)i_ptr,(int)stub);
f76eeef9 203 return i_ptr;
57871462 204}
205
f968d35d 206// find where external branch is liked to using addr of it's stub:
207// get address that insn one after stub loads (dyna_linker arg1),
208// treat it as a pointer to branch insn,
209// return addr where that branch jumps to
57871462 210int get_pointer(void *stub)
211{
212 //printf("get_pointer(%x)\n",(int)stub);
213 int *ptr=(int *)(stub+4);
f968d35d 214 assert((*ptr&0x0fff0000)==0x059f0000);
57871462 215 u_int offset=*ptr&0xfff;
216 int **l_ptr=(void *)ptr+offset+8;
217 int *i_ptr=*l_ptr;
218 assert((*i_ptr&0x0f000000)==0x0a000000);
219 return (int)i_ptr+((*i_ptr<<8)>>6)+8;
220}
221
222// Find the "clean" entry point from a "dirty" entry point
223// by skipping past the call to verify_code
224u_int get_clean_addr(int addr)
225{
226 int *ptr=(int *)addr;
665f33e1 227 #ifndef HAVE_ARMV7
57871462 228 ptr+=4;
229 #else
230 ptr+=6;
231 #endif
232 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
233 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
234 ptr++;
235 if((*ptr&0xFF000000)==0xea000000) {
236 return (int)ptr+((*ptr<<8)>>6)+8; // follow jump
237 }
238 return (u_int)ptr;
239}
240
241int verify_dirty(int addr)
242{
243 u_int *ptr=(u_int *)addr;
665f33e1 244 #ifndef HAVE_ARMV7
57871462 245 // get from literal pool
15776b68 246 assert((*ptr&0xFFFF0000)==0xe59f0000);
57871462 247 u_int offset=*ptr&0xfff;
248 u_int *l_ptr=(void *)ptr+offset+8;
249 u_int source=l_ptr[0];
250 u_int copy=l_ptr[1];
251 u_int len=l_ptr[2];
252 ptr+=4;
253 #else
254 // ARMv7 movw/movt
255 assert((*ptr&0xFFF00000)==0xe3000000);
256 u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
257 u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
258 u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
259 ptr+=6;
260 #endif
261 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
262 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
63cb0298 263#ifndef DISABLE_TLB
cfcba99a 264 u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl
57871462 265 if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) {
266 unsigned int page=source>>12;
267 unsigned int map_value=memory_map[page];
268 if(map_value>=0x80000000) return 0;
269 while(page<((source+len-1)>>12)) {
270 if((memory_map[++page]<<2)!=(map_value<<2)) return 0;
271 }
272 source = source+(map_value<<2);
273 }
63cb0298 274#endif
57871462 275 //printf("verify_dirty: %x %x %x\n",source,copy,len);
276 return !memcmp((void *)source,(void *)copy,len);
277}
278
279// This doesn't necessarily find all clean entry points, just
280// guarantees that it's not dirty
281int isclean(int addr)
282{
665f33e1 283 #ifndef HAVE_ARMV7
57871462 284 int *ptr=((u_int *)addr)+4;
285 #else
286 int *ptr=((u_int *)addr)+6;
287 #endif
288 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
289 if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction
290 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0;
291 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_vm) return 0;
292 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_ds) return 0;
293 return 1;
294}
295
4a35de07 296// get source that block at addr was compiled from (host pointers)
57871462 297void get_bounds(int addr,u_int *start,u_int *end)
298{
299 u_int *ptr=(u_int *)addr;
665f33e1 300 #ifndef HAVE_ARMV7
57871462 301 // get from literal pool
15776b68 302 assert((*ptr&0xFFFF0000)==0xe59f0000);
57871462 303 u_int offset=*ptr&0xfff;
304 u_int *l_ptr=(void *)ptr+offset+8;
305 u_int source=l_ptr[0];
306 //u_int copy=l_ptr[1];
307 u_int len=l_ptr[2];
308 ptr+=4;
309 #else
310 // ARMv7 movw/movt
311 assert((*ptr&0xFFF00000)==0xe3000000);
312 u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
313 //u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
314 u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
315 ptr+=6;
316 #endif
317 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
318 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
63cb0298 319#ifndef DISABLE_TLB
cfcba99a 320 u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl
57871462 321 if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) {
322 if(memory_map[source>>12]>=0x80000000) source = 0;
323 else source = source+(memory_map[source>>12]<<2);
324 }
63cb0298 325#endif
57871462 326 *start=source;
327 *end=source+len;
328}
329
330/* Register allocation */
331
332// Note: registers are allocated clean (unmodified state)
333// if you intend to modify the register, you must call dirty_reg().
334void alloc_reg(struct regstat *cur,int i,signed char reg)
335{
336 int r,hr;
337 int preferred_reg = (reg&7);
338 if(reg==CCREG) preferred_reg=HOST_CCREG;
339 if(reg==PTEMP||reg==FTEMP) preferred_reg=12;
340
341 // Don't allocate unused registers
342 if((cur->u>>reg)&1) return;
343
344 // see if it's already allocated
345 for(hr=0;hr<HOST_REGS;hr++)
346 {
347 if(cur->regmap[hr]==reg) return;
348 }
349
350 // Keep the same mapping if the register was already allocated in a loop
351 preferred_reg = loop_reg(i,reg,preferred_reg);
352
353 // Try to allocate the preferred register
354 if(cur->regmap[preferred_reg]==-1) {
355 cur->regmap[preferred_reg]=reg;
356 cur->dirty&=~(1<<preferred_reg);
357 cur->isconst&=~(1<<preferred_reg);
358 return;
359 }
360 r=cur->regmap[preferred_reg];
361 if(r<64&&((cur->u>>r)&1)) {
362 cur->regmap[preferred_reg]=reg;
363 cur->dirty&=~(1<<preferred_reg);
364 cur->isconst&=~(1<<preferred_reg);
365 return;
366 }
367 if(r>=64&&((cur->uu>>(r&63))&1)) {
368 cur->regmap[preferred_reg]=reg;
369 cur->dirty&=~(1<<preferred_reg);
370 cur->isconst&=~(1<<preferred_reg);
371 return;
372 }
373
374 // Clear any unneeded registers
375 // We try to keep the mapping consistent, if possible, because it
376 // makes branches easier (especially loops). So we try to allocate
377 // first (see above) before removing old mappings. If this is not
378 // possible then go ahead and clear out the registers that are no
379 // longer needed.
380 for(hr=0;hr<HOST_REGS;hr++)
381 {
382 r=cur->regmap[hr];
383 if(r>=0) {
384 if(r<64) {
385 if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
386 }
387 else
388 {
389 if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;}
390 }
391 }
392 }
393 // Try to allocate any available register, but prefer
394 // registers that have not been used recently.
395 if(i>0) {
396 for(hr=0;hr<HOST_REGS;hr++) {
397 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
398 if(regs[i-1].regmap[hr]!=rs1[i-1]&&regs[i-1].regmap[hr]!=rs2[i-1]&&regs[i-1].regmap[hr]!=rt1[i-1]&&regs[i-1].regmap[hr]!=rt2[i-1]) {
399 cur->regmap[hr]=reg;
400 cur->dirty&=~(1<<hr);
401 cur->isconst&=~(1<<hr);
402 return;
403 }
404 }
405 }
406 }
407 // Try to allocate any available register
408 for(hr=0;hr<HOST_REGS;hr++) {
409 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
410 cur->regmap[hr]=reg;
411 cur->dirty&=~(1<<hr);
412 cur->isconst&=~(1<<hr);
413 return;
414 }
415 }
416
417 // Ok, now we have to evict someone
418 // Pick a register we hopefully won't need soon
419 u_char hsn[MAXREG+1];
420 memset(hsn,10,sizeof(hsn));
421 int j;
422 lsn(hsn,i,&preferred_reg);
423 //printf("eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",cur->regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]);
424 //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
425 if(i>0) {
426 // Don't evict the cycle count at entry points, otherwise the entry
427 // stub will have to write it.
428 if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
429 if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2;
430 for(j=10;j>=3;j--)
431 {
432 // Alloc preferred register if available
433 if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
434 for(hr=0;hr<HOST_REGS;hr++) {
435 // Evict both parts of a 64-bit register
436 if((cur->regmap[hr]&63)==r) {
437 cur->regmap[hr]=-1;
438 cur->dirty&=~(1<<hr);
439 cur->isconst&=~(1<<hr);
440 }
441 }
442 cur->regmap[preferred_reg]=reg;
443 return;
444 }
445 for(r=1;r<=MAXREG;r++)
446 {
447 if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
448 for(hr=0;hr<HOST_REGS;hr++) {
449 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
450 if(cur->regmap[hr]==r+64) {
451 cur->regmap[hr]=reg;
452 cur->dirty&=~(1<<hr);
453 cur->isconst&=~(1<<hr);
454 return;
455 }
456 }
457 }
458 for(hr=0;hr<HOST_REGS;hr++) {
459 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
460 if(cur->regmap[hr]==r) {
461 cur->regmap[hr]=reg;
462 cur->dirty&=~(1<<hr);
463 cur->isconst&=~(1<<hr);
464 return;
465 }
466 }
467 }
468 }
469 }
470 }
471 }
472 for(j=10;j>=0;j--)
473 {
474 for(r=1;r<=MAXREG;r++)
475 {
476 if(hsn[r]==j) {
477 for(hr=0;hr<HOST_REGS;hr++) {
478 if(cur->regmap[hr]==r+64) {
479 cur->regmap[hr]=reg;
480 cur->dirty&=~(1<<hr);
481 cur->isconst&=~(1<<hr);
482 return;
483 }
484 }
485 for(hr=0;hr<HOST_REGS;hr++) {
486 if(cur->regmap[hr]==r) {
487 cur->regmap[hr]=reg;
488 cur->dirty&=~(1<<hr);
489 cur->isconst&=~(1<<hr);
490 return;
491 }
492 }
493 }
494 }
495 }
c43b5311 496 SysPrintf("This shouldn't happen (alloc_reg)");exit(1);
57871462 497}
498
499void alloc_reg64(struct regstat *cur,int i,signed char reg)
500{
501 int preferred_reg = 8+(reg&1);
502 int r,hr;
503
504 // allocate the lower 32 bits
505 alloc_reg(cur,i,reg);
506
507 // Don't allocate unused registers
508 if((cur->uu>>reg)&1) return;
509
510 // see if the upper half is already allocated
511 for(hr=0;hr<HOST_REGS;hr++)
512 {
513 if(cur->regmap[hr]==reg+64) return;
514 }
515
516 // Keep the same mapping if the register was already allocated in a loop
517 preferred_reg = loop_reg(i,reg,preferred_reg);
518
519 // Try to allocate the preferred register
520 if(cur->regmap[preferred_reg]==-1) {
521 cur->regmap[preferred_reg]=reg|64;
522 cur->dirty&=~(1<<preferred_reg);
523 cur->isconst&=~(1<<preferred_reg);
524 return;
525 }
526 r=cur->regmap[preferred_reg];
527 if(r<64&&((cur->u>>r)&1)) {
528 cur->regmap[preferred_reg]=reg|64;
529 cur->dirty&=~(1<<preferred_reg);
530 cur->isconst&=~(1<<preferred_reg);
531 return;
532 }
533 if(r>=64&&((cur->uu>>(r&63))&1)) {
534 cur->regmap[preferred_reg]=reg|64;
535 cur->dirty&=~(1<<preferred_reg);
536 cur->isconst&=~(1<<preferred_reg);
537 return;
538 }
539
540 // Clear any unneeded registers
541 // We try to keep the mapping consistent, if possible, because it
542 // makes branches easier (especially loops). So we try to allocate
543 // first (see above) before removing old mappings. If this is not
544 // possible then go ahead and clear out the registers that are no
545 // longer needed.
546 for(hr=HOST_REGS-1;hr>=0;hr--)
547 {
548 r=cur->regmap[hr];
549 if(r>=0) {
550 if(r<64) {
551 if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
552 }
553 else
554 {
555 if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;}
556 }
557 }
558 }
559 // Try to allocate any available register, but prefer
560 // registers that have not been used recently.
561 if(i>0) {
562 for(hr=0;hr<HOST_REGS;hr++) {
563 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
564 if(regs[i-1].regmap[hr]!=rs1[i-1]&&regs[i-1].regmap[hr]!=rs2[i-1]&&regs[i-1].regmap[hr]!=rt1[i-1]&&regs[i-1].regmap[hr]!=rt2[i-1]) {
565 cur->regmap[hr]=reg|64;
566 cur->dirty&=~(1<<hr);
567 cur->isconst&=~(1<<hr);
568 return;
569 }
570 }
571 }
572 }
573 // Try to allocate any available register
574 for(hr=0;hr<HOST_REGS;hr++) {
575 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
576 cur->regmap[hr]=reg|64;
577 cur->dirty&=~(1<<hr);
578 cur->isconst&=~(1<<hr);
579 return;
580 }
581 }
582
583 // Ok, now we have to evict someone
584 // Pick a register we hopefully won't need soon
585 u_char hsn[MAXREG+1];
586 memset(hsn,10,sizeof(hsn));
587 int j;
588 lsn(hsn,i,&preferred_reg);
589 //printf("eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",cur->regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]);
590 //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
591 if(i>0) {
592 // Don't evict the cycle count at entry points, otherwise the entry
593 // stub will have to write it.
594 if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
595 if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2;
596 for(j=10;j>=3;j--)
597 {
598 // Alloc preferred register if available
599 if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
600 for(hr=0;hr<HOST_REGS;hr++) {
601 // Evict both parts of a 64-bit register
602 if((cur->regmap[hr]&63)==r) {
603 cur->regmap[hr]=-1;
604 cur->dirty&=~(1<<hr);
605 cur->isconst&=~(1<<hr);
606 }
607 }
608 cur->regmap[preferred_reg]=reg|64;
609 return;
610 }
611 for(r=1;r<=MAXREG;r++)
612 {
613 if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
614 for(hr=0;hr<HOST_REGS;hr++) {
615 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
616 if(cur->regmap[hr]==r+64) {
617 cur->regmap[hr]=reg|64;
618 cur->dirty&=~(1<<hr);
619 cur->isconst&=~(1<<hr);
620 return;
621 }
622 }
623 }
624 for(hr=0;hr<HOST_REGS;hr++) {
625 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
626 if(cur->regmap[hr]==r) {
627 cur->regmap[hr]=reg|64;
628 cur->dirty&=~(1<<hr);
629 cur->isconst&=~(1<<hr);
630 return;
631 }
632 }
633 }
634 }
635 }
636 }
637 }
638 for(j=10;j>=0;j--)
639 {
640 for(r=1;r<=MAXREG;r++)
641 {
642 if(hsn[r]==j) {
643 for(hr=0;hr<HOST_REGS;hr++) {
644 if(cur->regmap[hr]==r+64) {
645 cur->regmap[hr]=reg|64;
646 cur->dirty&=~(1<<hr);
647 cur->isconst&=~(1<<hr);
648 return;
649 }
650 }
651 for(hr=0;hr<HOST_REGS;hr++) {
652 if(cur->regmap[hr]==r) {
653 cur->regmap[hr]=reg|64;
654 cur->dirty&=~(1<<hr);
655 cur->isconst&=~(1<<hr);
656 return;
657 }
658 }
659 }
660 }
661 }
c43b5311 662 SysPrintf("This shouldn't happen");exit(1);
57871462 663}
664
665// Allocate a temporary register. This is done without regard to
666// dirty status or whether the register we request is on the unneeded list
667// Note: This will only allocate one register, even if called multiple times
668void alloc_reg_temp(struct regstat *cur,int i,signed char reg)
669{
670 int r,hr;
671 int preferred_reg = -1;
672
673 // see if it's already allocated
674 for(hr=0;hr<HOST_REGS;hr++)
675 {
676 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==reg) return;
677 }
678
679 // Try to allocate any available register
680 for(hr=HOST_REGS-1;hr>=0;hr--) {
681 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
682 cur->regmap[hr]=reg;
683 cur->dirty&=~(1<<hr);
684 cur->isconst&=~(1<<hr);
685 return;
686 }
687 }
688
689 // Find an unneeded register
690 for(hr=HOST_REGS-1;hr>=0;hr--)
691 {
692 r=cur->regmap[hr];
693 if(r>=0) {
694 if(r<64) {
695 if((cur->u>>r)&1) {
696 if(i==0||((unneeded_reg[i-1]>>r)&1)) {
697 cur->regmap[hr]=reg;
698 cur->dirty&=~(1<<hr);
699 cur->isconst&=~(1<<hr);
700 return;
701 }
702 }
703 }
704 else
705 {
706 if((cur->uu>>(r&63))&1) {
707 if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) {
708 cur->regmap[hr]=reg;
709 cur->dirty&=~(1<<hr);
710 cur->isconst&=~(1<<hr);
711 return;
712 }
713 }
714 }
715 }
716 }
717
718 // Ok, now we have to evict someone
719 // Pick a register we hopefully won't need soon
720 // TODO: we might want to follow unconditional jumps here
721 // TODO: get rid of dupe code and make this into a function
722 u_char hsn[MAXREG+1];
723 memset(hsn,10,sizeof(hsn));
724 int j;
725 lsn(hsn,i,&preferred_reg);
726 //printf("hsn: %d %d %d %d %d %d %d\n",hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
727 if(i>0) {
728 // Don't evict the cycle count at entry points, otherwise the entry
729 // stub will have to write it.
730 if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
731 if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2;
732 for(j=10;j>=3;j--)
733 {
734 for(r=1;r<=MAXREG;r++)
735 {
736 if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
737 for(hr=0;hr<HOST_REGS;hr++) {
738 if(hr!=HOST_CCREG||hsn[CCREG]>2) {
739 if(cur->regmap[hr]==r+64) {
740 cur->regmap[hr]=reg;
741 cur->dirty&=~(1<<hr);
742 cur->isconst&=~(1<<hr);
743 return;
744 }
745 }
746 }
747 for(hr=0;hr<HOST_REGS;hr++) {
748 if(hr!=HOST_CCREG||hsn[CCREG]>2) {
749 if(cur->regmap[hr]==r) {
750 cur->regmap[hr]=reg;
751 cur->dirty&=~(1<<hr);
752 cur->isconst&=~(1<<hr);
753 return;
754 }
755 }
756 }
757 }
758 }
759 }
760 }
761 for(j=10;j>=0;j--)
762 {
763 for(r=1;r<=MAXREG;r++)
764 {
765 if(hsn[r]==j) {
766 for(hr=0;hr<HOST_REGS;hr++) {
767 if(cur->regmap[hr]==r+64) {
768 cur->regmap[hr]=reg;
769 cur->dirty&=~(1<<hr);
770 cur->isconst&=~(1<<hr);
771 return;
772 }
773 }
774 for(hr=0;hr<HOST_REGS;hr++) {
775 if(cur->regmap[hr]==r) {
776 cur->regmap[hr]=reg;
777 cur->dirty&=~(1<<hr);
778 cur->isconst&=~(1<<hr);
779 return;
780 }
781 }
782 }
783 }
784 }
c43b5311 785 SysPrintf("This shouldn't happen");exit(1);
57871462 786}
787// Allocate a specific ARM register.
788void alloc_arm_reg(struct regstat *cur,int i,signed char reg,char hr)
789{
790 int n;
f776eb14 791 int dirty=0;
57871462 792
793 // see if it's already allocated (and dealloc it)
794 for(n=0;n<HOST_REGS;n++)
795 {
f776eb14 796 if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
797 dirty=(cur->dirty>>n)&1;
798 cur->regmap[n]=-1;
799 }
57871462 800 }
801
802 cur->regmap[hr]=reg;
803 cur->dirty&=~(1<<hr);
f776eb14 804 cur->dirty|=dirty<<hr;
57871462 805 cur->isconst&=~(1<<hr);
806}
807
808// Alloc cycle count into dedicated register
809alloc_cc(struct regstat *cur,int i)
810{
811 alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
812}
813
814/* Special alloc */
815
816
817/* Assembler */
818
819char regname[16][4] = {
820 "r0",
821 "r1",
822 "r2",
823 "r3",
824 "r4",
825 "r5",
826 "r6",
827 "r7",
828 "r8",
829 "r9",
830 "r10",
831 "fp",
832 "r12",
833 "sp",
834 "lr",
835 "pc"};
836
837void output_byte(u_char byte)
838{
839 *(out++)=byte;
840}
841void output_modrm(u_char mod,u_char rm,u_char ext)
842{
843 assert(mod<4);
844 assert(rm<8);
845 assert(ext<8);
846 u_char byte=(mod<<6)|(ext<<3)|rm;
847 *(out++)=byte;
848}
849void output_sib(u_char scale,u_char index,u_char base)
850{
851 assert(scale<4);
852 assert(index<8);
853 assert(base<8);
854 u_char byte=(scale<<6)|(index<<3)|base;
855 *(out++)=byte;
856}
857void output_w32(u_int word)
858{
859 *((u_int *)out)=word;
860 out+=4;
861}
862u_int rd_rn_rm(u_int rd, u_int rn, u_int rm)
863{
864 assert(rd<16);
865 assert(rn<16);
866 assert(rm<16);
867 return((rn<<16)|(rd<<12)|rm);
868}
869u_int rd_rn_imm_shift(u_int rd, u_int rn, u_int imm, u_int shift)
870{
871 assert(rd<16);
872 assert(rn<16);
873 assert(imm<256);
874 assert((shift&1)==0);
875 return((rn<<16)|(rd<<12)|(((32-shift)&30)<<7)|imm);
876}
877u_int genimm(u_int imm,u_int *encoded)
878{
c2e3bd42 879 *encoded=0;
880 if(imm==0) return 1;
57871462 881 int i=32;
882 while(i>0)
883 {
884 if(imm<256) {
885 *encoded=((i&30)<<7)|imm;
886 return 1;
887 }
888 imm=(imm>>2)|(imm<<30);i-=2;
889 }
890 return 0;
891}
cfbd3c6e 892void genimm_checked(u_int imm,u_int *encoded)
893{
894 u_int ret=genimm(imm,encoded);
895 assert(ret);
896}
57871462 897u_int genjmp(u_int addr)
898{
899 int offset=addr-(int)out-8;
e80343e2 900 if(offset<-33554432||offset>=33554432) {
901 if (addr>2) {
c43b5311 902 SysPrintf("genjmp: out of range: %08x\n", offset);
e80343e2 903 exit(1);
904 }
905 return 0;
906 }
57871462 907 return ((u_int)offset>>2)&0xffffff;
908}
909
910void emit_mov(int rs,int rt)
911{
912 assem_debug("mov %s,%s\n",regname[rt],regname[rs]);
913 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs));
914}
915
916void emit_movs(int rs,int rt)
917{
918 assem_debug("movs %s,%s\n",regname[rt],regname[rs]);
919 output_w32(0xe1b00000|rd_rn_rm(rt,0,rs));
920}
921
922void emit_add(int rs1,int rs2,int rt)
923{
924 assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
925 output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2));
926}
927
928void emit_adds(int rs1,int rs2,int rt)
929{
930 assem_debug("adds %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
931 output_w32(0xe0900000|rd_rn_rm(rt,rs1,rs2));
932}
933
934void emit_adcs(int rs1,int rs2,int rt)
935{
936 assem_debug("adcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
937 output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2));
938}
939
940void emit_sbc(int rs1,int rs2,int rt)
941{
942 assem_debug("sbc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
943 output_w32(0xe0c00000|rd_rn_rm(rt,rs1,rs2));
944}
945
946void emit_sbcs(int rs1,int rs2,int rt)
947{
948 assem_debug("sbcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
949 output_w32(0xe0d00000|rd_rn_rm(rt,rs1,rs2));
950}
951
952void emit_neg(int rs, int rt)
953{
954 assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
955 output_w32(0xe2600000|rd_rn_rm(rt,rs,0));
956}
957
958void emit_negs(int rs, int rt)
959{
960 assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]);
961 output_w32(0xe2700000|rd_rn_rm(rt,rs,0));
962}
963
964void emit_sub(int rs1,int rs2,int rt)
965{
966 assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
967 output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2));
968}
969
970void emit_subs(int rs1,int rs2,int rt)
971{
972 assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
973 output_w32(0xe0500000|rd_rn_rm(rt,rs1,rs2));
974}
975
976void emit_zeroreg(int rt)
977{
978 assem_debug("mov %s,#0\n",regname[rt]);
979 output_w32(0xe3a00000|rd_rn_rm(rt,0,0));
980}
981
790ee18e 982void emit_loadlp(u_int imm,u_int rt)
983{
984 add_literal((int)out,imm);
985 assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
986 output_w32(0xe5900000|rd_rn_rm(rt,15,0));
987}
988void emit_movw(u_int imm,u_int rt)
989{
990 assert(imm<65536);
991 assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
992 output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
993}
994void emit_movt(u_int imm,u_int rt)
995{
996 assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
997 output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
998}
999void emit_movimm(u_int imm,u_int rt)
1000{
1001 u_int armval;
1002 if(genimm(imm,&armval)) {
1003 assem_debug("mov %s,#%d\n",regname[rt],imm);
1004 output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
1005 }else if(genimm(~imm,&armval)) {
1006 assem_debug("mvn %s,#%d\n",regname[rt],imm);
1007 output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
1008 }else if(imm<65536) {
665f33e1 1009 #ifndef HAVE_ARMV7
790ee18e 1010 assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
1011 output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
1012 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
1013 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1014 #else
1015 emit_movw(imm,rt);
1016 #endif
1017 }else{
665f33e1 1018 #ifndef HAVE_ARMV7
790ee18e 1019 emit_loadlp(imm,rt);
1020 #else
1021 emit_movw(imm&0x0000FFFF,rt);
1022 emit_movt(imm&0xFFFF0000,rt);
1023 #endif
1024 }
1025}
1026void emit_pcreladdr(u_int rt)
1027{
1028 assem_debug("add %s,pc,#?\n",regname[rt]);
1029 output_w32(0xe2800000|rd_rn_rm(rt,15,0));
1030}
1031
57871462 1032void emit_loadreg(int r, int hr)
1033{
3d624f89 1034#ifdef FORCE32
1035 if(r&64) {
c43b5311 1036 SysPrintf("64bit load in 32bit mode!\n");
7f2607ea 1037 assert(0);
1038 return;
3d624f89 1039 }
1040#endif
57871462 1041 if((r&63)==0)
1042 emit_zeroreg(hr);
1043 else {
3d624f89 1044 int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
57871462 1045 if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4);
1046 if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4);
1047 if(r==CCREG) addr=(int)&cycle_count;
1048 if(r==CSREG) addr=(int)&Status;
1049 if(r==FSREG) addr=(int)&FCR31;
1050 if(r==INVCP) addr=(int)&invc_ptr;
1051 u_int offset = addr-(u_int)&dynarec_local;
1052 assert(offset<4096);
1053 assem_debug("ldr %s,fp+%d\n",regname[hr],offset);
1054 output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset);
1055 }
1056}
1057void emit_storereg(int r, int hr)
1058{
3d624f89 1059#ifdef FORCE32
1060 if(r&64) {
c43b5311 1061 SysPrintf("64bit store in 32bit mode!\n");
7f2607ea 1062 assert(0);
1063 return;
3d624f89 1064 }
1065#endif
1066 int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
57871462 1067 if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4);
1068 if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4);
1069 if(r==CCREG) addr=(int)&cycle_count;
1070 if(r==FSREG) addr=(int)&FCR31;
1071 u_int offset = addr-(u_int)&dynarec_local;
1072 assert(offset<4096);
1073 assem_debug("str %s,fp+%d\n",regname[hr],offset);
1074 output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset);
1075}
1076
1077void emit_test(int rs, int rt)
1078{
1079 assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
1080 output_w32(0xe1100000|rd_rn_rm(0,rs,rt));
1081}
1082
1083void emit_testimm(int rs,int imm)
1084{
1085 u_int armval;
5a05d80c 1086 assem_debug("tst %s,#%d\n",regname[rs],imm);
cfbd3c6e 1087 genimm_checked(imm,&armval);
57871462 1088 output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval);
1089}
1090
b9b61529 1091void emit_testeqimm(int rs,int imm)
1092{
1093 u_int armval;
1094 assem_debug("tsteq %s,$%d\n",regname[rs],imm);
cfbd3c6e 1095 genimm_checked(imm,&armval);
b9b61529 1096 output_w32(0x03100000|rd_rn_rm(0,rs,0)|armval);
1097}
1098
57871462 1099void emit_not(int rs,int rt)
1100{
1101 assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
1102 output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
1103}
1104
b9b61529 1105void emit_mvnmi(int rs,int rt)
1106{
1107 assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
1108 output_w32(0x41e00000|rd_rn_rm(rt,0,rs));
1109}
1110
57871462 1111void emit_and(u_int rs1,u_int rs2,u_int rt)
1112{
1113 assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1114 output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2));
1115}
1116
1117void emit_or(u_int rs1,u_int rs2,u_int rt)
1118{
1119 assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1120 output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2));
1121}
1122void emit_or_and_set_flags(int rs1,int rs2,int rt)
1123{
1124 assem_debug("orrs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1125 output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2));
1126}
1127
f70d384d 1128void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
1129{
1130 assert(rs<16);
1131 assert(rt<16);
1132 assert(imm<32);
1133 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
1134 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|(imm<<7));
1135}
1136
576bbd8f 1137void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
1138{
1139 assert(rs<16);
1140 assert(rt<16);
1141 assert(imm<32);
1142 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
1143 output_w32(0xe1800020|rd_rn_rm(rt,rt,rs)|(imm<<7));
1144}
1145
57871462 1146void emit_xor(u_int rs1,u_int rs2,u_int rt)
1147{
1148 assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1149 output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
1150}
1151
57871462 1152void emit_addimm(u_int rs,int imm,u_int rt)
1153{
1154 assert(rs<16);
1155 assert(rt<16);
1156 if(imm!=0) {
57871462 1157 u_int armval;
1158 if(genimm(imm,&armval)) {
1159 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm);
1160 output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
1161 }else if(genimm(-imm,&armval)) {
8a0a8423 1162 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-imm);
57871462 1163 output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
1164 }else if(imm<0) {
ffb0b9e0 1165 assert(imm>-65536);
57871462 1166 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00);
1167 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
1168 output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8));
1169 output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
1170 }else{
ffb0b9e0 1171 assert(imm<65536);
57871462 1172 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
1173 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
1174 output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8));
1175 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1176 }
1177 }
1178 else if(rs!=rt) emit_mov(rs,rt);
1179}
1180
1181void emit_addimm_and_set_flags(int imm,int rt)
1182{
1183 assert(imm>-65536&&imm<65536);
1184 u_int armval;
1185 if(genimm(imm,&armval)) {
1186 assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm);
1187 output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval);
1188 }else if(genimm(-imm,&armval)) {
1189 assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],imm);
1190 output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval);
1191 }else if(imm<0) {
1192 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF00);
1193 assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
1194 output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8));
1195 output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
1196 }else{
1197 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF00);
1198 assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
1199 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8));
1200 output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1201 }
1202}
1203void emit_addimm_no_flags(u_int imm,u_int rt)
1204{
1205 emit_addimm(rt,imm,rt);
1206}
1207
1208void emit_addnop(u_int r)
1209{
1210 assert(r<16);
1211 assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]);
1212 output_w32(0xe2800000|rd_rn_rm(r,r,0));
1213}
1214
1215void emit_adcimm(u_int rs,int imm,u_int rt)
1216{
1217 u_int armval;
cfbd3c6e 1218 genimm_checked(imm,&armval);
57871462 1219 assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm);
1220 output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval);
1221}
1222/*void emit_sbcimm(int imm,u_int rt)
1223{
1224 u_int armval;
cfbd3c6e 1225 genimm_checked(imm,&armval);
57871462 1226 assem_debug("sbc %s,%s,#%d\n",regname[rt],regname[rt],imm);
1227 output_w32(0xe2c00000|rd_rn_rm(rt,rt,0)|armval);
1228}*/
1229void emit_sbbimm(int imm,u_int rt)
1230{
1231 assem_debug("sbb $%d,%%%s\n",imm,regname[rt]);
1232 assert(rt<8);
1233 if(imm<128&&imm>=-128) {
1234 output_byte(0x83);
1235 output_modrm(3,rt,3);
1236 output_byte(imm);
1237 }
1238 else
1239 {
1240 output_byte(0x81);
1241 output_modrm(3,rt,3);
1242 output_w32(imm);
1243 }
1244}
1245void emit_rscimm(int rs,int imm,u_int rt)
1246{
1247 assert(0);
1248 u_int armval;
cfbd3c6e 1249 genimm_checked(imm,&armval);
57871462 1250 assem_debug("rsc %s,%s,#%d\n",regname[rt],regname[rs],imm);
1251 output_w32(0xe2e00000|rd_rn_rm(rt,rs,0)|armval);
1252}
1253
1254void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl)
1255{
1256 // TODO: if(genimm(imm,&armval)) ...
1257 // else
1258 emit_movimm(imm,HOST_TEMPREG);
1259 emit_adds(HOST_TEMPREG,rsl,rtl);
1260 emit_adcimm(rsh,0,rth);
1261}
1262
1263void emit_sbb(int rs1,int rs2)
1264{
1265 assem_debug("sbb %%%s,%%%s\n",regname[rs2],regname[rs1]);
1266 output_byte(0x19);
1267 output_modrm(3,rs1,rs2);
1268}
1269
1270void emit_andimm(int rs,int imm,int rt)
1271{
1272 u_int armval;
790ee18e 1273 if(imm==0) {
1274 emit_zeroreg(rt);
1275 }else if(genimm(imm,&armval)) {
57871462 1276 assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm);
1277 output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval);
1278 }else if(genimm(~imm,&armval)) {
1279 assem_debug("bic %s,%s,#%d\n",regname[rt],regname[rs],imm);
1280 output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval);
1281 }else if(imm==65535) {
665f33e1 1282 #ifndef HAVE_ARMV7
57871462 1283 assem_debug("bic %s,%s,#FF000000\n",regname[rt],regname[rs]);
1284 output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF);
1285 assem_debug("bic %s,%s,#00FF0000\n",regname[rt],regname[rt]);
1286 output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF);
1287 #else
1288 assem_debug("uxth %s,%s\n",regname[rt],regname[rs]);
1289 output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs));
1290 #endif
1291 }else{
1292 assert(imm>0&&imm<65535);
665f33e1 1293 #ifndef HAVE_ARMV7
57871462 1294 assem_debug("mov r14,#%d\n",imm&0xFF00);
1295 output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8));
1296 assem_debug("add r14,r14,#%d\n",imm&0xFF);
1297 output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0));
1298 #else
1299 emit_movw(imm,HOST_TEMPREG);
1300 #endif
1301 assem_debug("and %s,%s,r14\n",regname[rt],regname[rs]);
1302 output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG));
1303 }
1304}
1305
1306void emit_orimm(int rs,int imm,int rt)
1307{
1308 u_int armval;
790ee18e 1309 if(imm==0) {
1310 if(rs!=rt) emit_mov(rs,rt);
1311 }else if(genimm(imm,&armval)) {
57871462 1312 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1313 output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval);
1314 }else{
1315 assert(imm>0&&imm<65536);
1316 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
1317 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
1318 output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8));
1319 output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1320 }
1321}
1322
1323void emit_xorimm(int rs,int imm,int rt)
1324{
57871462 1325 u_int armval;
790ee18e 1326 if(imm==0) {
1327 if(rs!=rt) emit_mov(rs,rt);
1328 }else if(genimm(imm,&armval)) {
57871462 1329 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm);
1330 output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval);
1331 }else{
514ed0d9 1332 assert(imm>0&&imm<65536);
57871462 1333 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
1334 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
1335 output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8));
1336 output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1337 }
1338}
1339
1340void emit_shlimm(int rs,u_int imm,int rt)
1341{
1342 assert(imm>0);
1343 assert(imm<32);
1344 //if(imm==1) ...
1345 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
1346 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1347}
1348
c6c3b1b3 1349void emit_lsls_imm(int rs,int imm,int rt)
1350{
1351 assert(imm>0);
1352 assert(imm<32);
1353 assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
1354 output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1355}
1356
665f33e1 1357void emit_lslpls_imm(int rs,int imm,int rt)
1358{
1359 assert(imm>0);
1360 assert(imm<32);
1361 assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
1362 output_w32(0x51b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1363}
1364
57871462 1365void emit_shrimm(int rs,u_int imm,int rt)
1366{
1367 assert(imm>0);
1368 assert(imm<32);
1369 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1370 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
1371}
1372
1373void emit_sarimm(int rs,u_int imm,int rt)
1374{
1375 assert(imm>0);
1376 assert(imm<32);
1377 assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1378 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7));
1379}
1380
1381void emit_rorimm(int rs,u_int imm,int rt)
1382{
1383 assert(imm>0);
1384 assert(imm<32);
1385 assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
1386 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7));
1387}
1388
1389void emit_shldimm(int rs,int rs2,u_int imm,int rt)
1390{
1391 assem_debug("shld %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm);
1392 assert(imm>0);
1393 assert(imm<32);
1394 //if(imm==1) ...
1395 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
1396 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1397 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs2],32-imm);
1398 output_w32(0xe1800020|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7));
1399}
1400
1401void emit_shrdimm(int rs,int rs2,u_int imm,int rt)
1402{
1403 assem_debug("shrd %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm);
1404 assert(imm>0);
1405 assert(imm<32);
1406 //if(imm==1) ...
1407 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1408 output_w32(0xe1a00020|rd_rn_rm(rt,0,rs)|(imm<<7));
1409 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs2],32-imm);
1410 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7));
1411}
1412
b9b61529 1413void emit_signextend16(int rs,int rt)
1414{
665f33e1 1415 #ifndef HAVE_ARMV7
b9b61529 1416 emit_shlimm(rs,16,rt);
1417 emit_sarimm(rt,16,rt);
1418 #else
1419 assem_debug("sxth %s,%s\n",regname[rt],regname[rs]);
1420 output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs));
1421 #endif
1422}
1423
c6c3b1b3 1424void emit_signextend8(int rs,int rt)
1425{
665f33e1 1426 #ifndef HAVE_ARMV7
c6c3b1b3 1427 emit_shlimm(rs,24,rt);
1428 emit_sarimm(rt,24,rt);
1429 #else
1430 assem_debug("sxtb %s,%s\n",regname[rt],regname[rs]);
1431 output_w32(0xe6af0070|rd_rn_rm(rt,0,rs));
1432 #endif
1433}
1434
57871462 1435void emit_shl(u_int rs,u_int shift,u_int rt)
1436{
1437 assert(rs<16);
1438 assert(rt<16);
1439 assert(shift<16);
1440 //if(imm==1) ...
1441 assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
1442 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8));
1443}
1444void emit_shr(u_int rs,u_int shift,u_int rt)
1445{
1446 assert(rs<16);
1447 assert(rt<16);
1448 assert(shift<16);
1449 assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
1450 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8));
1451}
1452void emit_sar(u_int rs,u_int shift,u_int rt)
1453{
1454 assert(rs<16);
1455 assert(rt<16);
1456 assert(shift<16);
1457 assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
1458 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
1459}
1460void emit_shlcl(int r)
1461{
1462 assem_debug("shl %%%s,%%cl\n",regname[r]);
1463 assert(0);
1464}
1465void emit_shrcl(int r)
1466{
1467 assem_debug("shr %%%s,%%cl\n",regname[r]);
1468 assert(0);
1469}
1470void emit_sarcl(int r)
1471{
1472 assem_debug("sar %%%s,%%cl\n",regname[r]);
1473 assert(0);
1474}
1475
1476void emit_shldcl(int r1,int r2)
1477{
1478 assem_debug("shld %%%s,%%%s,%%cl\n",regname[r1],regname[r2]);
1479 assert(0);
1480}
1481void emit_shrdcl(int r1,int r2)
1482{
1483 assem_debug("shrd %%%s,%%%s,%%cl\n",regname[r1],regname[r2]);
1484 assert(0);
1485}
1486void emit_orrshl(u_int rs,u_int shift,u_int rt)
1487{
1488 assert(rs<16);
1489 assert(rt<16);
1490 assert(shift<16);
1491 assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
1492 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
1493}
1494void emit_orrshr(u_int rs,u_int shift,u_int rt)
1495{
1496 assert(rs<16);
1497 assert(rt<16);
1498 assert(shift<16);
1499 assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
1500 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8));
1501}
1502
1503void emit_cmpimm(int rs,int imm)
1504{
1505 u_int armval;
1506 if(genimm(imm,&armval)) {
5a05d80c 1507 assem_debug("cmp %s,#%d\n",regname[rs],imm);
57871462 1508 output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval);
1509 }else if(genimm(-imm,&armval)) {
5a05d80c 1510 assem_debug("cmn %s,#%d\n",regname[rs],imm);
57871462 1511 output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval);
1512 }else if(imm>0) {
1513 assert(imm<65536);
57871462 1514 emit_movimm(imm,HOST_TEMPREG);
57871462 1515 assem_debug("cmp %s,r14\n",regname[rs]);
1516 output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG));
1517 }else{
1518 assert(imm>-65536);
57871462 1519 emit_movimm(-imm,HOST_TEMPREG);
57871462 1520 assem_debug("cmn %s,r14\n",regname[rs]);
1521 output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG));
1522 }
1523}
1524
1525void emit_cmovne(u_int *addr,int rt)
1526{
1527 assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]);
1528 assert(0);
1529}
1530void emit_cmovl(u_int *addr,int rt)
1531{
1532 assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]);
1533 assert(0);
1534}
1535void emit_cmovs(u_int *addr,int rt)
1536{
1537 assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]);
1538 assert(0);
1539}
1540void emit_cmovne_imm(int imm,int rt)
1541{
1542 assem_debug("movne %s,#%d\n",regname[rt],imm);
1543 u_int armval;
cfbd3c6e 1544 genimm_checked(imm,&armval);
57871462 1545 output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval);
1546}
1547void emit_cmovl_imm(int imm,int rt)
1548{
1549 assem_debug("movlt %s,#%d\n",regname[rt],imm);
1550 u_int armval;
cfbd3c6e 1551 genimm_checked(imm,&armval);
57871462 1552 output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval);
1553}
1554void emit_cmovb_imm(int imm,int rt)
1555{
1556 assem_debug("movcc %s,#%d\n",regname[rt],imm);
1557 u_int armval;
cfbd3c6e 1558 genimm_checked(imm,&armval);
57871462 1559 output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
1560}
1561void emit_cmovs_imm(int imm,int rt)
1562{
1563 assem_debug("movmi %s,#%d\n",regname[rt],imm);
1564 u_int armval;
cfbd3c6e 1565 genimm_checked(imm,&armval);
57871462 1566 output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval);
1567}
1568void emit_cmove_reg(int rs,int rt)
1569{
1570 assem_debug("moveq %s,%s\n",regname[rt],regname[rs]);
1571 output_w32(0x01a00000|rd_rn_rm(rt,0,rs));
1572}
1573void emit_cmovne_reg(int rs,int rt)
1574{
1575 assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
1576 output_w32(0x11a00000|rd_rn_rm(rt,0,rs));
1577}
1578void emit_cmovl_reg(int rs,int rt)
1579{
1580 assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
1581 output_w32(0xb1a00000|rd_rn_rm(rt,0,rs));
1582}
1583void emit_cmovs_reg(int rs,int rt)
1584{
1585 assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
1586 output_w32(0x41a00000|rd_rn_rm(rt,0,rs));
1587}
1588
1589void emit_slti32(int rs,int imm,int rt)
1590{
1591 if(rs!=rt) emit_zeroreg(rt);
1592 emit_cmpimm(rs,imm);
1593 if(rs==rt) emit_movimm(0,rt);
1594 emit_cmovl_imm(1,rt);
1595}
1596void emit_sltiu32(int rs,int imm,int rt)
1597{
1598 if(rs!=rt) emit_zeroreg(rt);
1599 emit_cmpimm(rs,imm);
1600 if(rs==rt) emit_movimm(0,rt);
1601 emit_cmovb_imm(1,rt);
1602}
1603void emit_slti64_32(int rsh,int rsl,int imm,int rt)
1604{
1605 assert(rsh!=rt);
1606 emit_slti32(rsl,imm,rt);
1607 if(imm>=0)
1608 {
1609 emit_test(rsh,rsh);
1610 emit_cmovne_imm(0,rt);
1611 emit_cmovs_imm(1,rt);
1612 }
1613 else
1614 {
1615 emit_cmpimm(rsh,-1);
1616 emit_cmovne_imm(0,rt);
1617 emit_cmovl_imm(1,rt);
1618 }
1619}
1620void emit_sltiu64_32(int rsh,int rsl,int imm,int rt)
1621{
1622 assert(rsh!=rt);
1623 emit_sltiu32(rsl,imm,rt);
1624 if(imm>=0)
1625 {
1626 emit_test(rsh,rsh);
1627 emit_cmovne_imm(0,rt);
1628 }
1629 else
1630 {
1631 emit_cmpimm(rsh,-1);
1632 emit_cmovne_imm(1,rt);
1633 }
1634}
1635
1636void emit_cmp(int rs,int rt)
1637{
1638 assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
1639 output_w32(0xe1500000|rd_rn_rm(0,rs,rt));
1640}
1641void emit_set_gz32(int rs, int rt)
1642{
1643 //assem_debug("set_gz32\n");
1644 emit_cmpimm(rs,1);
1645 emit_movimm(1,rt);
1646 emit_cmovl_imm(0,rt);
1647}
1648void emit_set_nz32(int rs, int rt)
1649{
1650 //assem_debug("set_nz32\n");
1651 if(rs!=rt) emit_movs(rs,rt);
1652 else emit_test(rs,rs);
1653 emit_cmovne_imm(1,rt);
1654}
1655void emit_set_gz64_32(int rsh, int rsl, int rt)
1656{
1657 //assem_debug("set_gz64\n");
1658 emit_set_gz32(rsl,rt);
1659 emit_test(rsh,rsh);
1660 emit_cmovne_imm(1,rt);
1661 emit_cmovs_imm(0,rt);
1662}
1663void emit_set_nz64_32(int rsh, int rsl, int rt)
1664{
1665 //assem_debug("set_nz64\n");
1666 emit_or_and_set_flags(rsh,rsl,rt);
1667 emit_cmovne_imm(1,rt);
1668}
1669void emit_set_if_less32(int rs1, int rs2, int rt)
1670{
1671 //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1672 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1673 emit_cmp(rs1,rs2);
1674 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1675 emit_cmovl_imm(1,rt);
1676}
1677void emit_set_if_carry32(int rs1, int rs2, int rt)
1678{
1679 //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1680 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1681 emit_cmp(rs1,rs2);
1682 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1683 emit_cmovb_imm(1,rt);
1684}
1685void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt)
1686{
1687 //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]);
1688 assert(u1!=rt);
1689 assert(u2!=rt);
1690 emit_cmp(l1,l2);
1691 emit_movimm(0,rt);
1692 emit_sbcs(u1,u2,HOST_TEMPREG);
1693 emit_cmovl_imm(1,rt);
1694}
1695void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt)
1696{
1697 //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]);
1698 assert(u1!=rt);
1699 assert(u2!=rt);
1700 emit_cmp(l1,l2);
1701 emit_movimm(0,rt);
1702 emit_sbcs(u1,u2,HOST_TEMPREG);
1703 emit_cmovb_imm(1,rt);
1704}
1705
1706void emit_call(int a)
1707{
1708 assem_debug("bl %x (%x+%x)\n",a,(int)out,a-(int)out-8);
1709 u_int offset=genjmp(a);
1710 output_w32(0xeb000000|offset);
1711}
1712void emit_jmp(int a)
1713{
1714 assem_debug("b %x (%x+%x)\n",a,(int)out,a-(int)out-8);
1715 u_int offset=genjmp(a);
1716 output_w32(0xea000000|offset);
1717}
1718void emit_jne(int a)
1719{
1720 assem_debug("bne %x\n",a);
1721 u_int offset=genjmp(a);
1722 output_w32(0x1a000000|offset);
1723}
1724void emit_jeq(int a)
1725{
1726 assem_debug("beq %x\n",a);
1727 u_int offset=genjmp(a);
1728 output_w32(0x0a000000|offset);
1729}
1730void emit_js(int a)
1731{
1732 assem_debug("bmi %x\n",a);
1733 u_int offset=genjmp(a);
1734 output_w32(0x4a000000|offset);
1735}
1736void emit_jns(int a)
1737{
1738 assem_debug("bpl %x\n",a);
1739 u_int offset=genjmp(a);
1740 output_w32(0x5a000000|offset);
1741}
1742void emit_jl(int a)
1743{
1744 assem_debug("blt %x\n",a);
1745 u_int offset=genjmp(a);
1746 output_w32(0xba000000|offset);
1747}
1748void emit_jge(int a)
1749{
1750 assem_debug("bge %x\n",a);
1751 u_int offset=genjmp(a);
1752 output_w32(0xaa000000|offset);
1753}
1754void emit_jno(int a)
1755{
1756 assem_debug("bvc %x\n",a);
1757 u_int offset=genjmp(a);
1758 output_w32(0x7a000000|offset);
1759}
1760void emit_jc(int a)
1761{
1762 assem_debug("bcs %x\n",a);
1763 u_int offset=genjmp(a);
1764 output_w32(0x2a000000|offset);
1765}
1766void emit_jcc(int a)
1767{
1768 assem_debug("bcc %x\n",a);
1769 u_int offset=genjmp(a);
1770 output_w32(0x3a000000|offset);
1771}
1772
1773void emit_pushimm(int imm)
1774{
1775 assem_debug("push $%x\n",imm);
1776 assert(0);
1777}
1778void emit_pusha()
1779{
1780 assem_debug("pusha\n");
1781 assert(0);
1782}
1783void emit_popa()
1784{
1785 assem_debug("popa\n");
1786 assert(0);
1787}
1788void emit_pushreg(u_int r)
1789{
1790 assem_debug("push %%%s\n",regname[r]);
1791 assert(0);
1792}
1793void emit_popreg(u_int r)
1794{
1795 assem_debug("pop %%%s\n",regname[r]);
1796 assert(0);
1797}
1798void emit_callreg(u_int r)
1799{
c6c3b1b3 1800 assert(r<15);
1801 assem_debug("blx %s\n",regname[r]);
1802 output_w32(0xe12fff30|r);
57871462 1803}
1804void emit_jmpreg(u_int r)
1805{
1806 assem_debug("mov pc,%s\n",regname[r]);
1807 output_w32(0xe1a00000|rd_rn_rm(15,0,r));
1808}
1809
1810void emit_readword_indexed(int offset, int rs, int rt)
1811{
1812 assert(offset>-4096&&offset<4096);
1813 assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
1814 if(offset>=0) {
1815 output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset);
1816 }else{
1817 output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset));
1818 }
1819}
1820void emit_readword_dualindexedx4(int rs1, int rs2, int rt)
1821{
1822 assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
1823 output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100);
1824}
c6c3b1b3 1825void emit_ldrcc_dualindexed(int rs1, int rs2, int rt)
1826{
1827 assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1828 output_w32(0x37900000|rd_rn_rm(rt,rs1,rs2));
1829}
1830void emit_ldrccb_dualindexed(int rs1, int rs2, int rt)
1831{
1832 assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1833 output_w32(0x37d00000|rd_rn_rm(rt,rs1,rs2));
1834}
1835void emit_ldrccsb_dualindexed(int rs1, int rs2, int rt)
1836{
1837 assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1838 output_w32(0x319000d0|rd_rn_rm(rt,rs1,rs2));
1839}
1840void emit_ldrcch_dualindexed(int rs1, int rs2, int rt)
1841{
1842 assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1843 output_w32(0x319000b0|rd_rn_rm(rt,rs1,rs2));
1844}
1845void emit_ldrccsh_dualindexed(int rs1, int rs2, int rt)
1846{
1847 assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1848 output_w32(0x319000f0|rd_rn_rm(rt,rs1,rs2));
1849}
57871462 1850void emit_readword_indexed_tlb(int addr, int rs, int map, int rt)
1851{
1852 if(map<0) emit_readword_indexed(addr, rs, rt);
1853 else {
1854 assert(addr==0);
1855 emit_readword_dualindexedx4(rs, map, rt);
1856 }
1857}
1858void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl)
1859{
1860 if(map<0) {
1861 if(rh>=0) emit_readword_indexed(addr, rs, rh);
1862 emit_readword_indexed(addr+4, rs, rl);
1863 }else{
1864 assert(rh!=rs);
1865 if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh);
1866 emit_addimm(map,1,map);
1867 emit_readword_indexed_tlb(addr, rs, map, rl);
1868 }
1869}
1870void emit_movsbl_indexed(int offset, int rs, int rt)
1871{
1872 assert(offset>-256&&offset<256);
1873 assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
1874 if(offset>=0) {
1875 output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1876 }else{
1877 output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1878 }
1879}
1880void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt)
1881{
1882 if(map<0) emit_movsbl_indexed(addr, rs, rt);
1883 else {
1884 if(addr==0) {
1885 emit_shlimm(map,2,map);
1886 assem_debug("ldrsb %s,%s+%s\n",regname[rt],regname[rs],regname[map]);
1887 output_w32(0xe19000d0|rd_rn_rm(rt,rs,map));
1888 }else{
1889 assert(addr>-256&&addr<256);
1890 assem_debug("add %s,%s,%s,lsl #2\n",regname[rt],regname[rs],regname[map]);
1891 output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7));
1892 emit_movsbl_indexed(addr, rt, rt);
1893 }
1894 }
1895}
1896void emit_movswl_indexed(int offset, int rs, int rt)
1897{
1898 assert(offset>-256&&offset<256);
1899 assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
1900 if(offset>=0) {
1901 output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1902 }else{
1903 output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1904 }
1905}
1906void emit_movzbl_indexed(int offset, int rs, int rt)
1907{
1908 assert(offset>-4096&&offset<4096);
1909 assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
1910 if(offset>=0) {
1911 output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset);
1912 }else{
1913 output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset));
1914 }
1915}
1916void emit_movzbl_dualindexedx4(int rs1, int rs2, int rt)
1917{
1918 assem_debug("ldrb %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
1919 output_w32(0xe7d00000|rd_rn_rm(rt,rs1,rs2)|0x100);
1920}
1921void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt)
1922{
1923 if(map<0) emit_movzbl_indexed(addr, rs, rt);
1924 else {
1925 if(addr==0) {
1926 emit_movzbl_dualindexedx4(rs, map, rt);
1927 }else{
1928 emit_addimm(rs,addr,rt);
1929 emit_movzbl_dualindexedx4(rt, map, rt);
1930 }
1931 }
1932}
1933void emit_movzwl_indexed(int offset, int rs, int rt)
1934{
1935 assert(offset>-256&&offset<256);
1936 assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
1937 if(offset>=0) {
1938 output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1939 }else{
1940 output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1941 }
1942}
054175e9 1943static void emit_ldrd(int offset, int rs, int rt)
1944{
1945 assert(offset>-256&&offset<256);
1946 assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset);
1947 if(offset>=0) {
1948 output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1949 }else{
1950 output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1951 }
1952}
57871462 1953void emit_readword(int addr, int rt)
1954{
1955 u_int offset = addr-(u_int)&dynarec_local;
1956 assert(offset<4096);
1957 assem_debug("ldr %s,fp+%d\n",regname[rt],offset);
1958 output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset);
1959}
1960void emit_movsbl(int addr, int rt)
1961{
1962 u_int offset = addr-(u_int)&dynarec_local;
1963 assert(offset<256);
1964 assem_debug("ldrsb %s,fp+%d\n",regname[rt],offset);
1965 output_w32(0xe1d000d0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
1966}
1967void emit_movswl(int addr, int rt)
1968{
1969 u_int offset = addr-(u_int)&dynarec_local;
1970 assert(offset<256);
1971 assem_debug("ldrsh %s,fp+%d\n",regname[rt],offset);
1972 output_w32(0xe1d000f0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
1973}
1974void emit_movzbl(int addr, int rt)
1975{
1976 u_int offset = addr-(u_int)&dynarec_local;
1977 assert(offset<4096);
1978 assem_debug("ldrb %s,fp+%d\n",regname[rt],offset);
1979 output_w32(0xe5d00000|rd_rn_rm(rt,FP,0)|offset);
1980}
1981void emit_movzwl(int addr, int rt)
1982{
1983 u_int offset = addr-(u_int)&dynarec_local;
1984 assert(offset<256);
1985 assem_debug("ldrh %s,fp+%d\n",regname[rt],offset);
1986 output_w32(0xe1d000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
1987}
1988void emit_movzwl_reg(int rs, int rt)
1989{
1990 assem_debug("movzwl %%%s,%%%s\n",regname[rs]+1,regname[rt]);
1991 assert(0);
1992}
1993
1994void emit_xchg(int rs, int rt)
1995{
1996 assem_debug("xchg %%%s,%%%s\n",regname[rs],regname[rt]);
1997 assert(0);
1998}
1999void emit_writeword_indexed(int rt, int offset, int rs)
2000{
2001 assert(offset>-4096&&offset<4096);
2002 assem_debug("str %s,%s+%d\n",regname[rt],regname[rs],offset);
2003 if(offset>=0) {
2004 output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset);
2005 }else{
2006 output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset));
2007 }
2008}
2009void emit_writeword_dualindexedx4(int rt, int rs1, int rs2)
2010{
2011 assem_debug("str %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
2012 output_w32(0xe7800000|rd_rn_rm(rt,rs1,rs2)|0x100);
2013}
2014void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map, int temp)
2015{
2016 if(map<0) emit_writeword_indexed(rt, addr, rs);
2017 else {
2018 assert(addr==0);
2019 emit_writeword_dualindexedx4(rt, rs, map);
2020 }
2021}
2022void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map, int temp)
2023{
2024 if(map<0) {
2025 if(rh>=0) emit_writeword_indexed(rh, addr, rs);
2026 emit_writeword_indexed(rl, addr+4, rs);
2027 }else{
2028 assert(rh>=0);
2029 if(temp!=rs) emit_addimm(map,1,temp);
2030 emit_writeword_indexed_tlb(rh, addr, rs, map, temp);
2031 if(temp!=rs) emit_writeword_indexed_tlb(rl, addr, rs, temp, temp);
2032 else {
2033 emit_addimm(rs,4,rs);
2034 emit_writeword_indexed_tlb(rl, addr, rs, map, temp);
2035 }
2036 }
2037}
2038void emit_writehword_indexed(int rt, int offset, int rs)
2039{
2040 assert(offset>-256&&offset<256);
2041 assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset);
2042 if(offset>=0) {
2043 output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
2044 }else{
2045 output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
2046 }
2047}
2048void emit_writebyte_indexed(int rt, int offset, int rs)
2049{
2050 assert(offset>-4096&&offset<4096);
2051 assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset);
2052 if(offset>=0) {
2053 output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset);
2054 }else{
2055 output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset));
2056 }
2057}
2058void emit_writebyte_dualindexedx4(int rt, int rs1, int rs2)
2059{
2060 assem_debug("strb %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
2061 output_w32(0xe7c00000|rd_rn_rm(rt,rs1,rs2)|0x100);
2062}
2063void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map, int temp)
2064{
2065 if(map<0) emit_writebyte_indexed(rt, addr, rs);
2066 else {
2067 if(addr==0) {
2068 emit_writebyte_dualindexedx4(rt, rs, map);
2069 }else{
2070 emit_addimm(rs,addr,temp);
2071 emit_writebyte_dualindexedx4(rt, temp, map);
2072 }
2073 }
2074}
b96d3df7 2075void emit_strcc_dualindexed(int rs1, int rs2, int rt)
2076{
2077 assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2078 output_w32(0x37800000|rd_rn_rm(rt,rs1,rs2));
2079}
2080void emit_strccb_dualindexed(int rs1, int rs2, int rt)
2081{
2082 assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2083 output_w32(0x37c00000|rd_rn_rm(rt,rs1,rs2));
2084}
2085void emit_strcch_dualindexed(int rs1, int rs2, int rt)
2086{
2087 assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2088 output_w32(0x318000b0|rd_rn_rm(rt,rs1,rs2));
2089}
57871462 2090void emit_writeword(int rt, int addr)
2091{
2092 u_int offset = addr-(u_int)&dynarec_local;
2093 assert(offset<4096);
2094 assem_debug("str %s,fp+%d\n",regname[rt],offset);
2095 output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset);
2096}
2097void emit_writehword(int rt, int addr)
2098{
2099 u_int offset = addr-(u_int)&dynarec_local;
2100 assert(offset<256);
2101 assem_debug("strh %s,fp+%d\n",regname[rt],offset);
2102 output_w32(0xe1c000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
2103}
2104void emit_writebyte(int rt, int addr)
2105{
2106 u_int offset = addr-(u_int)&dynarec_local;
2107 assert(offset<4096);
74426039 2108 assem_debug("strb %s,fp+%d\n",regname[rt],offset);
57871462 2109 output_w32(0xe5c00000|rd_rn_rm(rt,FP,0)|offset);
2110}
2111void emit_writeword_imm(int imm, int addr)
2112{
2113 assem_debug("movl $%x,%x\n",imm,addr);
2114 assert(0);
2115}
2116void emit_writebyte_imm(int imm, int addr)
2117{
2118 assem_debug("movb $%x,%x\n",imm,addr);
2119 assert(0);
2120}
2121
2122void emit_mul(int rs)
2123{
2124 assem_debug("mul %%%s\n",regname[rs]);
2125 assert(0);
2126}
2127void emit_imul(int rs)
2128{
2129 assem_debug("imul %%%s\n",regname[rs]);
2130 assert(0);
2131}
2132void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
2133{
2134 assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
2135 assert(rs1<16);
2136 assert(rs2<16);
2137 assert(hi<16);
2138 assert(lo<16);
2139 output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
2140}
2141void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
2142{
2143 assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
2144 assert(rs1<16);
2145 assert(rs2<16);
2146 assert(hi<16);
2147 assert(lo<16);
2148 output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
2149}
2150
2151void emit_div(int rs)
2152{
2153 assem_debug("div %%%s\n",regname[rs]);
2154 assert(0);
2155}
2156void emit_idiv(int rs)
2157{
2158 assem_debug("idiv %%%s\n",regname[rs]);
2159 assert(0);
2160}
2161void emit_cdq()
2162{
2163 assem_debug("cdq\n");
2164 assert(0);
2165}
2166
2167void emit_clz(int rs,int rt)
2168{
2169 assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
2170 output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs));
2171}
2172
2173void emit_subcs(int rs1,int rs2,int rt)
2174{
2175 assem_debug("subcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2176 output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2));
2177}
2178
2179void emit_shrcc_imm(int rs,u_int imm,int rt)
2180{
2181 assert(imm>0);
2182 assert(imm<32);
2183 assem_debug("lsrcc %s,%s,#%d\n",regname[rt],regname[rs],imm);
2184 output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
2185}
2186
b1be1eee 2187void emit_shrne_imm(int rs,u_int imm,int rt)
2188{
2189 assert(imm>0);
2190 assert(imm<32);
2191 assem_debug("lsrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2192 output_w32(0x11a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
2193}
2194
57871462 2195void emit_negmi(int rs, int rt)
2196{
2197 assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]);
2198 output_w32(0x42600000|rd_rn_rm(rt,rs,0));
2199}
2200
2201void emit_negsmi(int rs, int rt)
2202{
2203 assem_debug("rsbsmi %s,%s,#0\n",regname[rt],regname[rs]);
2204 output_w32(0x42700000|rd_rn_rm(rt,rs,0));
2205}
2206
2207void emit_orreq(u_int rs1,u_int rs2,u_int rt)
2208{
2209 assem_debug("orreq %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2210 output_w32(0x01800000|rd_rn_rm(rt,rs1,rs2));
2211}
2212
2213void emit_orrne(u_int rs1,u_int rs2,u_int rt)
2214{
2215 assem_debug("orrne %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2216 output_w32(0x11800000|rd_rn_rm(rt,rs1,rs2));
2217}
2218
2219void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
2220{
2221 assem_debug("bic %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2222 output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
2223}
2224
2225void emit_biceq_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
2226{
2227 assem_debug("biceq %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2228 output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
2229}
2230
2231void emit_bicne_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
2232{
2233 assem_debug("bicne %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2234 output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
2235}
2236
2237void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
2238{
2239 assem_debug("bic %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2240 output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
2241}
2242
2243void emit_biceq_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
2244{
2245 assem_debug("biceq %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2246 output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
2247}
2248
2249void emit_bicne_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
2250{
2251 assem_debug("bicne %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2252 output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
2253}
2254
2255void emit_teq(int rs, int rt)
2256{
2257 assem_debug("teq %s,%s\n",regname[rs],regname[rt]);
2258 output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
2259}
2260
2261void emit_rsbimm(int rs, int imm, int rt)
2262{
2263 u_int armval;
cfbd3c6e 2264 genimm_checked(imm,&armval);
57871462 2265 assem_debug("rsb %s,%s,#%d\n",regname[rt],regname[rs],imm);
2266 output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval);
2267}
2268
2269// Load 2 immediates optimizing for small code size
2270void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
2271{
2272 emit_movimm(imm1,rt1);
2273 u_int armval;
2274 if(genimm(imm2-imm1,&armval)) {
2275 assem_debug("add %s,%s,#%d\n",regname[rt2],regname[rt1],imm2-imm1);
2276 output_w32(0xe2800000|rd_rn_rm(rt2,rt1,0)|armval);
2277 }else if(genimm(imm1-imm2,&armval)) {
2278 assem_debug("sub %s,%s,#%d\n",regname[rt2],regname[rt1],imm1-imm2);
2279 output_w32(0xe2400000|rd_rn_rm(rt2,rt1,0)|armval);
2280 }
2281 else emit_movimm(imm2,rt2);
2282}
2283
2284// Conditionally select one of two immediates, optimizing for small code size
2285// This will only be called if HAVE_CMOV_IMM is defined
2286void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
2287{
2288 u_int armval;
2289 if(genimm(imm2-imm1,&armval)) {
2290 emit_movimm(imm1,rt);
2291 assem_debug("addne %s,%s,#%d\n",regname[rt],regname[rt],imm2-imm1);
2292 output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval);
2293 }else if(genimm(imm1-imm2,&armval)) {
2294 emit_movimm(imm1,rt);
2295 assem_debug("subne %s,%s,#%d\n",regname[rt],regname[rt],imm1-imm2);
2296 output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval);
2297 }
2298 else {
665f33e1 2299 #ifndef HAVE_ARMV7
57871462 2300 emit_movimm(imm1,rt);
2301 add_literal((int)out,imm2);
2302 assem_debug("ldrne %s,pc+? [=%x]\n",regname[rt],imm2);
2303 output_w32(0x15900000|rd_rn_rm(rt,15,0));
2304 #else
2305 emit_movw(imm1&0x0000FFFF,rt);
2306 if((imm1&0xFFFF)!=(imm2&0xFFFF)) {
2307 assem_debug("movwne %s,#%d (0x%x)\n",regname[rt],imm2&0xFFFF,imm2&0xFFFF);
2308 output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000));
2309 }
2310 emit_movt(imm1&0xFFFF0000,rt);
2311 if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) {
2312 assem_debug("movtne %s,#%d (0x%x)\n",regname[rt],imm2&0xffff0000,imm2&0xffff0000);
2313 output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000));
2314 }
2315 #endif
2316 }
2317}
2318
2319// special case for checking invalid_code
2320void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm)
2321{
2322 assert(0);
2323}
2324
2325// special case for checking invalid_code
2326void emit_cmpmem_indexedsr12_reg(int base,int r,int imm)
2327{
2328 assert(imm<128&&imm>=0);
2329 assert(r>=0&&r<16);
2330 assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
2331 output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620);
2332 emit_cmpimm(HOST_TEMPREG,imm);
2333}
2334
2335// special case for tlb mapping
2336void emit_addsr12(int rs1,int rs2,int rt)
2337{
2338 assem_debug("add %s,%s,%s lsr #12\n",regname[rt],regname[rs1],regname[rs2]);
2339 output_w32(0xe0800620|rd_rn_rm(rt,rs1,rs2));
2340}
2341
0bbd1454 2342void emit_callne(int a)
2343{
2344 assem_debug("blne %x\n",a);
2345 u_int offset=genjmp(a);
2346 output_w32(0x1b000000|offset);
2347}
2348
57871462 2349// Used to preload hash table entries
2350void emit_prefetch(void *addr)
2351{
2352 assem_debug("prefetch %x\n",(int)addr);
2353 output_byte(0x0F);
2354 output_byte(0x18);
2355 output_modrm(0,5,1);
2356 output_w32((int)addr);
2357}
2358void emit_prefetchreg(int r)
2359{
2360 assem_debug("pld %s\n",regname[r]);
2361 output_w32(0xf5d0f000|rd_rn_rm(0,r,0));
2362}
2363
2364// Special case for mini_ht
2365void emit_ldreq_indexed(int rs, u_int offset, int rt)
2366{
2367 assert(offset<4096);
2368 assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset);
2369 output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset);
2370}
2371
2372void emit_flds(int r,int sr)
2373{
2374 assem_debug("flds s%d,[%s]\n",sr,regname[r]);
2375 output_w32(0xed900a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16));
2376}
2377
2378void emit_vldr(int r,int vr)
2379{
2380 assem_debug("vldr d%d,[%s]\n",vr,regname[r]);
2381 output_w32(0xed900b00|(vr<<12)|(r<<16));
2382}
2383
2384void emit_fsts(int sr,int r)
2385{
2386 assem_debug("fsts s%d,[%s]\n",sr,regname[r]);
2387 output_w32(0xed800a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16));
2388}
2389
2390void emit_vstr(int vr,int r)
2391{
2392 assem_debug("vstr d%d,[%s]\n",vr,regname[r]);
2393 output_w32(0xed800b00|(vr<<12)|(r<<16));
2394}
2395
2396void emit_ftosizs(int s,int d)
2397{
2398 assem_debug("ftosizs s%d,s%d\n",d,s);
2399 output_w32(0xeebd0ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2400}
2401
2402void emit_ftosizd(int s,int d)
2403{
2404 assem_debug("ftosizd s%d,d%d\n",d,s);
2405 output_w32(0xeebd0bc0|((d&14)<<11)|((d&1)<<22)|(s&7));
2406}
2407
2408void emit_fsitos(int s,int d)
2409{
2410 assem_debug("fsitos s%d,s%d\n",d,s);
2411 output_w32(0xeeb80ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2412}
2413
2414void emit_fsitod(int s,int d)
2415{
2416 assem_debug("fsitod d%d,s%d\n",d,s);
2417 output_w32(0xeeb80bc0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5));
2418}
2419
2420void emit_fcvtds(int s,int d)
2421{
2422 assem_debug("fcvtds d%d,s%d\n",d,s);
2423 output_w32(0xeeb70ac0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5));
2424}
2425
2426void emit_fcvtsd(int s,int d)
2427{
2428 assem_debug("fcvtsd s%d,d%d\n",d,s);
2429 output_w32(0xeeb70bc0|((d&14)<<11)|((d&1)<<22)|(s&7));
2430}
2431
2432void emit_fsqrts(int s,int d)
2433{
2434 assem_debug("fsqrts d%d,s%d\n",d,s);
2435 output_w32(0xeeb10ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2436}
2437
2438void emit_fsqrtd(int s,int d)
2439{
2440 assem_debug("fsqrtd s%d,d%d\n",d,s);
2441 output_w32(0xeeb10bc0|((d&7)<<12)|(s&7));
2442}
2443
2444void emit_fabss(int s,int d)
2445{
2446 assem_debug("fabss d%d,s%d\n",d,s);
2447 output_w32(0xeeb00ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2448}
2449
2450void emit_fabsd(int s,int d)
2451{
2452 assem_debug("fabsd s%d,d%d\n",d,s);
2453 output_w32(0xeeb00bc0|((d&7)<<12)|(s&7));
2454}
2455
2456void emit_fnegs(int s,int d)
2457{
2458 assem_debug("fnegs d%d,s%d\n",d,s);
2459 output_w32(0xeeb10a40|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2460}
2461
2462void emit_fnegd(int s,int d)
2463{
2464 assem_debug("fnegd s%d,d%d\n",d,s);
2465 output_w32(0xeeb10b40|((d&7)<<12)|(s&7));
2466}
2467
2468void emit_fadds(int s1,int s2,int d)
2469{
2470 assem_debug("fadds s%d,s%d,s%d\n",d,s1,s2);
2471 output_w32(0xee300a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2472}
2473
2474void emit_faddd(int s1,int s2,int d)
2475{
2476 assem_debug("faddd d%d,d%d,d%d\n",d,s1,s2);
2477 output_w32(0xee300b00|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2478}
2479
2480void emit_fsubs(int s1,int s2,int d)
2481{
2482 assem_debug("fsubs s%d,s%d,s%d\n",d,s1,s2);
2483 output_w32(0xee300a40|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2484}
2485
2486void emit_fsubd(int s1,int s2,int d)
2487{
2488 assem_debug("fsubd d%d,d%d,d%d\n",d,s1,s2);
2489 output_w32(0xee300b40|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2490}
2491
2492void emit_fmuls(int s1,int s2,int d)
2493{
2494 assem_debug("fmuls s%d,s%d,s%d\n",d,s1,s2);
2495 output_w32(0xee200a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2496}
2497
2498void emit_fmuld(int s1,int s2,int d)
2499{
2500 assem_debug("fmuld d%d,d%d,d%d\n",d,s1,s2);
2501 output_w32(0xee200b00|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2502}
2503
2504void emit_fdivs(int s1,int s2,int d)
2505{
2506 assem_debug("fdivs s%d,s%d,s%d\n",d,s1,s2);
2507 output_w32(0xee800a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2508}
2509
2510void emit_fdivd(int s1,int s2,int d)
2511{
2512 assem_debug("fdivd d%d,d%d,d%d\n",d,s1,s2);
2513 output_w32(0xee800b00|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2514}
2515
2516void emit_fcmps(int x,int y)
2517{
2518 assem_debug("fcmps s14, s15\n");
2519 output_w32(0xeeb47a67);
2520}
2521
2522void emit_fcmpd(int x,int y)
2523{
2524 assem_debug("fcmpd d6, d7\n");
2525 output_w32(0xeeb46b47);
2526}
2527
2528void emit_fmstat()
2529{
2530 assem_debug("fmstat\n");
2531 output_w32(0xeef1fa10);
2532}
2533
2534void emit_bicne_imm(int rs,int imm,int rt)
2535{
2536 u_int armval;
cfbd3c6e 2537 genimm_checked(imm,&armval);
57871462 2538 assem_debug("bicne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2539 output_w32(0x13c00000|rd_rn_rm(rt,rs,0)|armval);
2540}
2541
2542void emit_biccs_imm(int rs,int imm,int rt)
2543{
2544 u_int armval;
cfbd3c6e 2545 genimm_checked(imm,&armval);
57871462 2546 assem_debug("biccs %s,%s,#%d\n",regname[rt],regname[rs],imm);
2547 output_w32(0x23c00000|rd_rn_rm(rt,rs,0)|armval);
2548}
2549
2550void emit_bicvc_imm(int rs,int imm,int rt)
2551{
2552 u_int armval;
cfbd3c6e 2553 genimm_checked(imm,&armval);
57871462 2554 assem_debug("bicvc %s,%s,#%d\n",regname[rt],regname[rs],imm);
2555 output_w32(0x73c00000|rd_rn_rm(rt,rs,0)|armval);
2556}
2557
2558void emit_bichi_imm(int rs,int imm,int rt)
2559{
2560 u_int armval;
cfbd3c6e 2561 genimm_checked(imm,&armval);
57871462 2562 assem_debug("bichi %s,%s,#%d\n",regname[rt],regname[rs],imm);
2563 output_w32(0x83c00000|rd_rn_rm(rt,rs,0)|armval);
2564}
2565
2566void emit_orrvs_imm(int rs,int imm,int rt)
2567{
2568 u_int armval;
cfbd3c6e 2569 genimm_checked(imm,&armval);
57871462 2570 assem_debug("orrvs %s,%s,#%d\n",regname[rt],regname[rs],imm);
2571 output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval);
2572}
2573
b9b61529 2574void emit_orrne_imm(int rs,int imm,int rt)
2575{
2576 u_int armval;
cfbd3c6e 2577 genimm_checked(imm,&armval);
b9b61529 2578 assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2579 output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval);
2580}
2581
2582void emit_andne_imm(int rs,int imm,int rt)
2583{
2584 u_int armval;
cfbd3c6e 2585 genimm_checked(imm,&armval);
b9b61529 2586 assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2587 output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval);
2588}
2589
665f33e1 2590void emit_addpl_imm(int rs,int imm,int rt)
2591{
2592 u_int armval;
2593 genimm_checked(imm,&armval);
2594 assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm);
2595 output_w32(0x52800000|rd_rn_rm(rt,rs,0)|armval);
2596}
2597
57871462 2598void emit_jno_unlikely(int a)
2599{
2600 //emit_jno(a);
2601 assem_debug("addvc pc,pc,#? (%x)\n",/*a-(int)out-8,*/a);
2602 output_w32(0x72800000|rd_rn_rm(15,15,0));
2603}
2604
054175e9 2605static void save_regs_all(u_int reglist)
57871462 2606{
054175e9 2607 int i;
57871462 2608 if(!reglist) return;
2609 assem_debug("stmia fp,{");
054175e9 2610 for(i=0;i<16;i++)
2611 if(reglist&(1<<i))
2612 assem_debug("r%d,",i);
57871462 2613 assem_debug("}\n");
2614 output_w32(0xe88b0000|reglist);
2615}
054175e9 2616static void restore_regs_all(u_int reglist)
57871462 2617{
054175e9 2618 int i;
57871462 2619 if(!reglist) return;
2620 assem_debug("ldmia fp,{");
054175e9 2621 for(i=0;i<16;i++)
2622 if(reglist&(1<<i))
2623 assem_debug("r%d,",i);
57871462 2624 assem_debug("}\n");
2625 output_w32(0xe89b0000|reglist);
2626}
054175e9 2627// Save registers before function call
2628static void save_regs(u_int reglist)
2629{
2630 reglist&=0x100f; // only save the caller-save registers, r0-r3, r12
2631 save_regs_all(reglist);
2632}
2633// Restore registers after function call
2634static void restore_regs(u_int reglist)
2635{
2636 reglist&=0x100f; // only restore the caller-save registers, r0-r3, r12
2637 restore_regs_all(reglist);
2638}
57871462 2639
2640// Write back consts using r14 so we don't disturb the other registers
2641void wb_consts(signed char i_regmap[],uint64_t i_is32,u_int i_dirty,int i)
2642{
2643 int hr;
2644 for(hr=0;hr<HOST_REGS;hr++) {
2645 if(hr!=EXCLUDE_REG&&i_regmap[hr]>=0&&((i_dirty>>hr)&1)) {
2646 if(((regs[i].isconst>>hr)&1)&&i_regmap[hr]>0) {
2647 if(i_regmap[hr]<64 || !((i_is32>>(i_regmap[hr]&63))&1) ) {
2648 int value=constmap[i][hr];
2649 if(value==0) {
2650 emit_zeroreg(HOST_TEMPREG);
2651 }
2652 else {
2653 emit_movimm(value,HOST_TEMPREG);
2654 }
2655 emit_storereg(i_regmap[hr],HOST_TEMPREG);
24385cae 2656#ifndef FORCE32
57871462 2657 if((i_is32>>i_regmap[hr])&1) {
2658 if(value!=-1&&value!=0) emit_sarimm(HOST_TEMPREG,31,HOST_TEMPREG);
2659 emit_storereg(i_regmap[hr]|64,HOST_TEMPREG);
2660 }
24385cae 2661#endif
57871462 2662 }
2663 }
2664 }
2665 }
2666}
2667
2668/* Stubs/epilogue */
2669
2670void literal_pool(int n)
2671{
2672 if(!literalcount) return;
2673 if(n) {
2674 if((int)out-literals[0][0]<4096-n) return;
2675 }
2676 u_int *ptr;
2677 int i;
2678 for(i=0;i<literalcount;i++)
2679 {
77750690 2680 u_int l_addr=(u_int)out;
2681 int j;
2682 for(j=0;j<i;j++) {
2683 if(literals[j][1]==literals[i][1]) {
2684 //printf("dup %08x\n",literals[i][1]);
2685 l_addr=literals[j][0];
2686 break;
2687 }
2688 }
57871462 2689 ptr=(u_int *)literals[i][0];
77750690 2690 u_int offset=l_addr-(u_int)ptr-8;
57871462 2691 assert(offset<4096);
2692 assert(!(offset&3));
2693 *ptr|=offset;
77750690 2694 if(l_addr==(u_int)out) {
2695 literals[i][0]=l_addr; // remember for dupes
2696 output_w32(literals[i][1]);
2697 }
57871462 2698 }
2699 literalcount=0;
2700}
2701
2702void literal_pool_jumpover(int n)
2703{
2704 if(!literalcount) return;
2705 if(n) {
2706 if((int)out-literals[0][0]<4096-n) return;
2707 }
2708 int jaddr=(int)out;
2709 emit_jmp(0);
2710 literal_pool(0);
2711 set_jump_target(jaddr,(int)out);
2712}
2713
c67af2ac 2714emit_extjump2(u_int addr, int target, int linker)
57871462 2715{
2716 u_char *ptr=(u_char *)addr;
2717 assert((ptr[3]&0x0e)==0xa);
2718 emit_loadlp(target,0);
2719 emit_loadlp(addr,1);
24385cae 2720 assert(addr>=BASE_ADDR&&addr<(BASE_ADDR+(1<<TARGET_SIZE_2)));
57871462 2721 //assert((target>=0x80000000&&target<0x80800000)||(target>0xA4000000&&target<0xA4001000));
2722//DEBUG >
2723#ifdef DEBUG_CYCLE_COUNT
2724 emit_readword((int)&last_count,ECX);
2725 emit_add(HOST_CCREG,ECX,HOST_CCREG);
2726 emit_readword((int)&next_interupt,ECX);
2727 emit_writeword(HOST_CCREG,(int)&Count);
2728 emit_sub(HOST_CCREG,ECX,HOST_CCREG);
2729 emit_writeword(ECX,(int)&last_count);
2730#endif
2731//DEBUG <
2732 emit_jmp(linker);
2733}
2734
2735emit_extjump(int addr, int target)
2736{
2737 emit_extjump2(addr, target, (int)dyna_linker);
2738}
2739emit_extjump_ds(int addr, int target)
2740{
2741 emit_extjump2(addr, target, (int)dyna_linker_ds);
2742}
2743
13e35c04 2744// put rt_val into rt, potentially making use of rs with value rs_val
2745static void emit_movimm_from(u_int rs_val,int rs,u_int rt_val,int rt)
2746{
8575a877 2747 u_int armval;
2748 int diff;
2749 if(genimm(rt_val,&armval)) {
2750 assem_debug("mov %s,#%d\n",regname[rt],rt_val);
2751 output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
2752 return;
2753 }
2754 if(genimm(~rt_val,&armval)) {
2755 assem_debug("mvn %s,#%d\n",regname[rt],rt_val);
2756 output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
2757 return;
2758 }
2759 diff=rt_val-rs_val;
2760 if(genimm(diff,&armval)) {
2761 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],diff);
2762 output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
2763 return;
2764 }else if(genimm(-diff,&armval)) {
2765 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-diff);
2766 output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
2767 return;
2768 }
2769 emit_movimm(rt_val,rt);
2770}
2771
2772// return 1 if above function can do it's job cheaply
2773static int is_similar_value(u_int v1,u_int v2)
2774{
13e35c04 2775 u_int xs;
8575a877 2776 int diff;
2777 if(v1==v2) return 1;
2778 diff=v2-v1;
2779 for(xs=diff;xs!=0&&(xs&3)==0;xs>>=2)
13e35c04 2780 ;
8575a877 2781 if(xs<0x100) return 1;
2782 for(xs=-diff;xs!=0&&(xs&3)==0;xs>>=2)
2783 ;
2784 if(xs<0x100) return 1;
2785 return 0;
13e35c04 2786}
cbbab9cd 2787
b96d3df7 2788// trashes r2
2789static void pass_args(int a0, int a1)
2790{
2791 if(a0==1&&a1==0) {
2792 // must swap
2793 emit_mov(a0,2); emit_mov(a1,1); emit_mov(2,0);
2794 }
2795 else if(a0!=0&&a1==0) {
2796 emit_mov(a1,1);
2797 if (a0>=0) emit_mov(a0,0);
2798 }
2799 else {
2800 if(a0>=0&&a0!=0) emit_mov(a0,0);
2801 if(a1>=0&&a1!=1) emit_mov(a1,1);
2802 }
2803}
2804
b1be1eee 2805static void mov_loadtype_adj(int type,int rs,int rt)
2806{
2807 switch(type) {
2808 case LOADB_STUB: emit_signextend8(rs,rt); break;
2809 case LOADBU_STUB: emit_andimm(rs,0xff,rt); break;
2810 case LOADH_STUB: emit_signextend16(rs,rt); break;
2811 case LOADHU_STUB: emit_andimm(rs,0xffff,rt); break;
2812 case LOADW_STUB: if(rs!=rt) emit_mov(rs,rt); break;
2813 default: assert(0);
2814 }
2815}
2816
2817#ifdef PCSX
2818#include "pcsxmem.h"
2819#include "pcsxmem_inline.c"
2820#endif
2821
57871462 2822do_readstub(int n)
2823{
2824 assem_debug("do_readstub %x\n",start+stubs[n][3]*4);
2825 literal_pool(256);
2826 set_jump_target(stubs[n][1],(int)out);
2827 int type=stubs[n][0];
2828 int i=stubs[n][3];
2829 int rs=stubs[n][4];
2830 struct regstat *i_regs=(struct regstat *)stubs[n][5];
2831 u_int reglist=stubs[n][7];
2832 signed char *i_regmap=i_regs->regmap;
2833 int addr=get_reg(i_regmap,AGEN1+(i&1));
2834 int rth,rt;
2835 int ds;
b9b61529 2836 if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) {
57871462 2837 rth=get_reg(i_regmap,FTEMP|64);
2838 rt=get_reg(i_regmap,FTEMP);
2839 }else{
2840 rth=get_reg(i_regmap,rt1[i]|64);
2841 rt=get_reg(i_regmap,rt1[i]);
2842 }
2843 assert(rs>=0);
c6c3b1b3 2844#ifdef PCSX
2845 int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0;
2846 reglist|=(1<<rs);
2847 for(r=0;r<=12;r++) {
2848 if(((1<<r)&0x13ff)&&((1<<r)&reglist)==0) {
2849 temp=r; break;
2850 }
2851 }
db829eeb 2852 if(rt>=0&&rt1[i]!=0)
c6c3b1b3 2853 reglist&=~(1<<rt);
2854 if(temp==-1) {
2855 save_regs(reglist);
2856 regs_saved=1;
2857 temp=(rs==0)?2:0;
2858 }
2859 if((regs_saved||(reglist&2)==0)&&temp!=1&&rs!=1)
2860 temp2=1;
2861 emit_readword((int)&mem_rtab,temp);
2862 emit_shrimm(rs,12,temp2);
2863 emit_readword_dualindexedx4(temp,temp2,temp2);
2864 emit_lsls_imm(temp2,1,temp2);
2865 if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
2866 switch(type) {
2867 case LOADB_STUB: emit_ldrccsb_dualindexed(temp2,rs,rt); break;
2868 case LOADBU_STUB: emit_ldrccb_dualindexed(temp2,rs,rt); break;
2869 case LOADH_STUB: emit_ldrccsh_dualindexed(temp2,rs,rt); break;
2870 case LOADHU_STUB: emit_ldrcch_dualindexed(temp2,rs,rt); break;
2871 case LOADW_STUB: emit_ldrcc_dualindexed(temp2,rs,rt); break;
2872 }
2873 }
2874 if(regs_saved) {
2875 restore_jump=(int)out;
2876 emit_jcc(0); // jump to reg restore
2877 }
2878 else
2879 emit_jcc(stubs[n][2]); // return address
2880
2881 if(!regs_saved)
2882 save_regs(reglist);
2883 int handler=0;
2884 if(type==LOADB_STUB||type==LOADBU_STUB)
2885 handler=(int)jump_handler_read8;
2886 if(type==LOADH_STUB||type==LOADHU_STUB)
2887 handler=(int)jump_handler_read16;
2888 if(type==LOADW_STUB)
2889 handler=(int)jump_handler_read32;
2890 assert(handler!=0);
b96d3df7 2891 pass_args(rs,temp2);
c6c3b1b3 2892 int cc=get_reg(i_regmap,CCREG);
2893 if(cc<0)
2894 emit_loadreg(CCREG,2);
2573466a 2895 emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
c6c3b1b3 2896 emit_call(handler);
2897 if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
b1be1eee 2898 mov_loadtype_adj(type,0,rt);
c6c3b1b3 2899 }
2900 if(restore_jump)
2901 set_jump_target(restore_jump,(int)out);
2902 restore_regs(reglist);
2903 emit_jmp(stubs[n][2]); // return address
2904#else // !PCSX
57871462 2905 if(addr<0) addr=rt;
535d208a 2906 if(addr<0&&itype[i]!=C1LS&&itype[i]!=C2LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1);
57871462 2907 assert(addr>=0);
2908 int ftable=0;
2909 if(type==LOADB_STUB||type==LOADBU_STUB)
2910 ftable=(int)readmemb;
2911 if(type==LOADH_STUB||type==LOADHU_STUB)
2912 ftable=(int)readmemh;
2913 if(type==LOADW_STUB)
2914 ftable=(int)readmem;
24385cae 2915#ifndef FORCE32
57871462 2916 if(type==LOADD_STUB)
2917 ftable=(int)readmemd;
24385cae 2918#endif
2919 assert(ftable!=0);
57871462 2920 emit_writeword(rs,(int)&address);
2921 //emit_pusha();
2922 save_regs(reglist);
97a238a6 2923#ifndef PCSX
57871462 2924 ds=i_regs!=&regs[i];
2925 int real_rs=(itype[i]==LOADLR)?-1:get_reg(i_regmap,rs1[i]);
2926 u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
2927 if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&0x100f,i);
2928 wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
2929 if(!ds) wb_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&~0x100f,i);
97a238a6 2930#endif
57871462 2931 emit_shrimm(rs,16,1);
2932 int cc=get_reg(i_regmap,CCREG);
2933 if(cc<0) {
2934 emit_loadreg(CCREG,2);
2935 }
2936 emit_movimm(ftable,0);
2937 emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
f51dc36c 2938#ifndef PCSX
57871462 2939 emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
f51dc36c 2940#endif
57871462 2941 //emit_readword((int)&last_count,temp);
2942 //emit_add(cc,temp,cc);
2943 //emit_writeword(cc,(int)&Count);
2944 //emit_mov(15,14);
2945 emit_call((int)&indirect_jump_indexed);
2946 //emit_callreg(rs);
2947 //emit_readword_dualindexedx4(rs,HOST_TEMPREG,15);
f51dc36c 2948#ifndef PCSX
57871462 2949 // We really shouldn't need to update the count here,
2950 // but not doing so causes random crashes...
2951 emit_readword((int)&Count,HOST_TEMPREG);
2952 emit_readword((int)&next_interupt,2);
2953 emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG);
2954 emit_writeword(2,(int)&last_count);
2955 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
2956 if(cc<0) {
2957 emit_storereg(CCREG,HOST_TEMPREG);
2958 }
f51dc36c 2959#endif
57871462 2960 //emit_popa();
2961 restore_regs(reglist);
2962 //if((cc=get_reg(regmap,CCREG))>=0) {
2963 // emit_loadreg(CCREG,cc);
2964 //}
f18c0f46 2965 if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
2966 assert(rt>=0);
2967 if(type==LOADB_STUB)
2968 emit_movsbl((int)&readmem_dword,rt);
2969 if(type==LOADBU_STUB)
2970 emit_movzbl((int)&readmem_dword,rt);
2971 if(type==LOADH_STUB)
2972 emit_movswl((int)&readmem_dword,rt);
2973 if(type==LOADHU_STUB)
2974 emit_movzwl((int)&readmem_dword,rt);
2975 if(type==LOADW_STUB)
2976 emit_readword((int)&readmem_dword,rt);
2977 if(type==LOADD_STUB) {
2978 emit_readword((int)&readmem_dword,rt);
2979 if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
2980 }
57871462 2981 }
2982 emit_jmp(stubs[n][2]); // return address
c6c3b1b3 2983#endif // !PCSX
57871462 2984}
2985
c6c3b1b3 2986#ifdef PCSX
2987// return memhandler, or get directly accessable address and return 0
2988u_int get_direct_memhandler(void *table,u_int addr,int type,u_int *addr_host)
2989{
2990 u_int l1,l2=0;
2991 l1=((u_int *)table)[addr>>12];
2992 if((l1&(1<<31))==0) {
2993 u_int v=l1<<1;
2994 *addr_host=v+addr;
2995 return 0;
2996 }
2997 else {
2998 l1<<=1;
2999 if(type==LOADB_STUB||type==LOADBU_STUB||type==STOREB_STUB)
3000 l2=((u_int *)l1)[0x1000/4 + 0x1000/2 + (addr&0xfff)];
b96d3df7 3001 else if(type==LOADH_STUB||type==LOADHU_STUB||type==STOREH_STUB)
c6c3b1b3 3002 l2=((u_int *)l1)[0x1000/4 + (addr&0xfff)/2];
3003 else
3004 l2=((u_int *)l1)[(addr&0xfff)/4];
3005 if((l2&(1<<31))==0) {
3006 u_int v=l2<<1;
3007 *addr_host=v+(addr&0xfff);
3008 return 0;
3009 }
3010 return l2<<1;
3011 }
3012}
3013#endif
3014
57871462 3015inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
3016{
3017 int rs=get_reg(regmap,target);
3018 int rth=get_reg(regmap,target|64);
3019 int rt=get_reg(regmap,target);
535d208a 3020 if(rs<0) rs=get_reg(regmap,-1);
57871462 3021 assert(rs>=0);
c6c3b1b3 3022#ifdef PCSX
b1be1eee 3023 u_int handler,host_addr=0,is_dynamic,far_call=0;
3024 int cc=get_reg(regmap,CCREG);
3025 if(pcsx_direct_read(type,addr,CLOCK_ADJUST(adj+1),cc,target?rs:-1,rt))
3026 return;
c6c3b1b3 3027 handler=get_direct_memhandler(mem_rtab,addr,type,&host_addr);
3028 if (handler==0) {
db829eeb 3029 if(rt<0||rt1[i]==0)
c6c3b1b3 3030 return;
13e35c04 3031 if(addr!=host_addr)
3032 emit_movimm_from(addr,rs,host_addr,rs);
c6c3b1b3 3033 switch(type) {
3034 case LOADB_STUB: emit_movsbl_indexed(0,rs,rt); break;
3035 case LOADBU_STUB: emit_movzbl_indexed(0,rs,rt); break;
3036 case LOADH_STUB: emit_movswl_indexed(0,rs,rt); break;
3037 case LOADHU_STUB: emit_movzwl_indexed(0,rs,rt); break;
3038 case LOADW_STUB: emit_readword_indexed(0,rs,rt); break;
3039 default: assert(0);
3040 }
3041 return;
3042 }
b1be1eee 3043 is_dynamic=pcsxmem_is_handler_dynamic(addr);
3044 if(is_dynamic) {
3045 if(type==LOADB_STUB||type==LOADBU_STUB)
3046 handler=(int)jump_handler_read8;
3047 if(type==LOADH_STUB||type==LOADHU_STUB)
3048 handler=(int)jump_handler_read16;
3049 if(type==LOADW_STUB)
3050 handler=(int)jump_handler_read32;
3051 }
c6c3b1b3 3052
3053 // call a memhandler
db829eeb 3054 if(rt>=0&&rt1[i]!=0)
c6c3b1b3 3055 reglist&=~(1<<rt);
3056 save_regs(reglist);
3057 if(target==0)
3058 emit_movimm(addr,0);
3059 else if(rs!=0)
3060 emit_mov(rs,0);
c6c3b1b3 3061 int offset=(int)handler-(int)out-8;
3062 if(offset<-33554432||offset>=33554432) {
3063 // unreachable memhandler, a plugin func perhaps
b1be1eee 3064 emit_movimm(handler,12);
3065 far_call=1;
3066 }
3067 if(cc<0)
3068 emit_loadreg(CCREG,2);
3069 if(is_dynamic) {
3070 emit_movimm(((u_int *)mem_rtab)[addr>>12]<<1,1);
3071 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
c6c3b1b3 3072 }
b1be1eee 3073 else {
3074 emit_readword((int)&last_count,3);
3075 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
3076 emit_add(2,3,2);
3077 emit_writeword(2,(int)&Count);
3078 }
3079
3080 if(far_call)
3081 emit_callreg(12);
c6c3b1b3 3082 else
3083 emit_call(handler);
b1be1eee 3084
db829eeb 3085 if(rt>=0&&rt1[i]!=0) {
c6c3b1b3 3086 switch(type) {
3087 case LOADB_STUB: emit_signextend8(0,rt); break;
3088 case LOADBU_STUB: emit_andimm(0,0xff,rt); break;
3089 case LOADH_STUB: emit_signextend16(0,rt); break;
3090 case LOADHU_STUB: emit_andimm(0,0xffff,rt); break;
3091 case LOADW_STUB: if(rt!=0) emit_mov(0,rt); break;
3092 default: assert(0);
3093 }
3094 }
3095 restore_regs(reglist);
3096#else // if !PCSX
57871462 3097 int ftable=0;
3098 if(type==LOADB_STUB||type==LOADBU_STUB)
3099 ftable=(int)readmemb;
3100 if(type==LOADH_STUB||type==LOADHU_STUB)
3101 ftable=(int)readmemh;
3102 if(type==LOADW_STUB)
3103 ftable=(int)readmem;
24385cae 3104#ifndef FORCE32
57871462 3105 if(type==LOADD_STUB)
3106 ftable=(int)readmemd;
24385cae 3107#endif
3108 assert(ftable!=0);
fd99c415 3109 if(target==0)
3110 emit_movimm(addr,rs);
57871462 3111 emit_writeword(rs,(int)&address);
3112 //emit_pusha();
3113 save_regs(reglist);
0c1fe38b 3114#ifndef PCSX
3115 if((signed int)addr>=(signed int)0xC0000000) {
3116 // Theoretically we can have a pagefault here, if the TLB has never
3117 // been enabled and the address is outside the range 80000000..BFFFFFFF
3118 // Write out the registers so the pagefault can be handled. This is
3119 // a very rare case and likely represents a bug.
3120 int ds=regmap!=regs[i].regmap;
3121 if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
3122 if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
3123 else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty);
3124 }
3125#endif
57871462 3126 //emit_shrimm(rs,16,1);
3127 int cc=get_reg(regmap,CCREG);
3128 if(cc<0) {
3129 emit_loadreg(CCREG,2);
3130 }
3131 //emit_movimm(ftable,0);
3132 emit_movimm(((u_int *)ftable)[addr>>16],0);
3133 //emit_readword((int)&last_count,12);
2573466a 3134 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
f51dc36c 3135#ifndef PCSX
57871462 3136 if((signed int)addr>=(signed int)0xC0000000) {
3137 // Pagefault address
3138 int ds=regmap!=regs[i].regmap;
3139 emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
3140 }
f51dc36c 3141#endif
57871462 3142 //emit_add(12,2,2);
3143 //emit_writeword(2,(int)&Count);
3144 //emit_call(((u_int *)ftable)[addr>>16]);
3145 emit_call((int)&indirect_jump);
f51dc36c 3146#ifndef PCSX
57871462 3147 // We really shouldn't need to update the count here,
3148 // but not doing so causes random crashes...
3149 emit_readword((int)&Count,HOST_TEMPREG);
3150 emit_readword((int)&next_interupt,2);
2573466a 3151 emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG);
57871462 3152 emit_writeword(2,(int)&last_count);
3153 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
3154 if(cc<0) {
3155 emit_storereg(CCREG,HOST_TEMPREG);
3156 }
f51dc36c 3157#endif
57871462 3158 //emit_popa();
3159 restore_regs(reglist);
fd99c415 3160 if(rt>=0) {
3161 if(type==LOADB_STUB)
3162 emit_movsbl((int)&readmem_dword,rt);
3163 if(type==LOADBU_STUB)
3164 emit_movzbl((int)&readmem_dword,rt);
3165 if(type==LOADH_STUB)
3166 emit_movswl((int)&readmem_dword,rt);
3167 if(type==LOADHU_STUB)
3168 emit_movzwl((int)&readmem_dword,rt);
3169 if(type==LOADW_STUB)
3170 emit_readword((int)&readmem_dword,rt);
3171 if(type==LOADD_STUB) {
3172 emit_readword((int)&readmem_dword,rt);
3173 if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
3174 }
57871462 3175 }
c6c3b1b3 3176#endif // !PCSX
57871462 3177}
3178
3179do_writestub(int n)
3180{
3181 assem_debug("do_writestub %x\n",start+stubs[n][3]*4);
3182 literal_pool(256);
3183 set_jump_target(stubs[n][1],(int)out);
3184 int type=stubs[n][0];
3185 int i=stubs[n][3];
3186 int rs=stubs[n][4];
3187 struct regstat *i_regs=(struct regstat *)stubs[n][5];
3188 u_int reglist=stubs[n][7];
3189 signed char *i_regmap=i_regs->regmap;
3190 int addr=get_reg(i_regmap,AGEN1+(i&1));
3191 int rth,rt,r;
3192 int ds;
b9b61529 3193 if(itype[i]==C1LS||itype[i]==C2LS) {
57871462 3194 rth=get_reg(i_regmap,FTEMP|64);
3195 rt=get_reg(i_regmap,r=FTEMP);
3196 }else{
3197 rth=get_reg(i_regmap,rs2[i]|64);
3198 rt=get_reg(i_regmap,r=rs2[i]);
3199 }
3200 assert(rs>=0);
3201 assert(rt>=0);
b96d3df7 3202#ifdef PCSX
3203 int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0,ra;
3204 int reglist2=reglist|(1<<rs)|(1<<rt);
3205 for(rtmp=0;rtmp<=12;rtmp++) {
3206 if(((1<<rtmp)&0x13ff)&&((1<<rtmp)&reglist2)==0) {
3207 temp=rtmp; break;
3208 }
3209 }
3210 if(temp==-1) {
3211 save_regs(reglist);
3212 regs_saved=1;
3213 for(rtmp=0;rtmp<=3;rtmp++)
3214 if(rtmp!=rs&&rtmp!=rt)
3215 {temp=rtmp;break;}
3216 }
3217 if((regs_saved||(reglist2&8)==0)&&temp!=3&&rs!=3&&rt!=3)
3218 temp2=3;
3219 emit_readword((int)&mem_wtab,temp);
3220 emit_shrimm(rs,12,temp2);
3221 emit_readword_dualindexedx4(temp,temp2,temp2);
3222 emit_lsls_imm(temp2,1,temp2);
3223 switch(type) {
3224 case STOREB_STUB: emit_strccb_dualindexed(temp2,rs,rt); break;
3225 case STOREH_STUB: emit_strcch_dualindexed(temp2,rs,rt); break;
3226 case STOREW_STUB: emit_strcc_dualindexed(temp2,rs,rt); break;
3227 default: assert(0);
3228 }
3229 if(regs_saved) {
3230 restore_jump=(int)out;
3231 emit_jcc(0); // jump to reg restore
3232 }
3233 else
3234 emit_jcc(stubs[n][2]); // return address (invcode check)
3235
3236 if(!regs_saved)
3237 save_regs(reglist);
3238 int handler=0;
3239 switch(type) {
3240 case STOREB_STUB: handler=(int)jump_handler_write8; break;
3241 case STOREH_STUB: handler=(int)jump_handler_write16; break;
3242 case STOREW_STUB: handler=(int)jump_handler_write32; break;
3243 }
3244 assert(handler!=0);
3245 pass_args(rs,rt);
3246 if(temp2!=3)
3247 emit_mov(temp2,3);
3248 int cc=get_reg(i_regmap,CCREG);
3249 if(cc<0)
3250 emit_loadreg(CCREG,2);
2573466a 3251 emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
b96d3df7 3252 // returns new cycle_count
3253 emit_call(handler);
2573466a 3254 emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc);
b96d3df7 3255 if(cc<0)
3256 emit_storereg(CCREG,2);
3257 if(restore_jump)
3258 set_jump_target(restore_jump,(int)out);
3259 restore_regs(reglist);
3260 ra=stubs[n][2];
b96d3df7 3261 emit_jmp(ra);
3262#else // if !PCSX
57871462 3263 if(addr<0) addr=get_reg(i_regmap,-1);
3264 assert(addr>=0);
3265 int ftable=0;
3266 if(type==STOREB_STUB)
3267 ftable=(int)writememb;
3268 if(type==STOREH_STUB)
3269 ftable=(int)writememh;
3270 if(type==STOREW_STUB)
3271 ftable=(int)writemem;
24385cae 3272#ifndef FORCE32
57871462 3273 if(type==STORED_STUB)
3274 ftable=(int)writememd;
24385cae 3275#endif
3276 assert(ftable!=0);
57871462 3277 emit_writeword(rs,(int)&address);
3278 //emit_shrimm(rs,16,rs);
3279 //emit_movmem_indexedx4(ftable,rs,rs);
3280 if(type==STOREB_STUB)
3281 emit_writebyte(rt,(int)&byte);
3282 if(type==STOREH_STUB)
3283 emit_writehword(rt,(int)&hword);
3284 if(type==STOREW_STUB)
3285 emit_writeword(rt,(int)&word);
3286 if(type==STORED_STUB) {
3d624f89 3287#ifndef FORCE32
57871462 3288 emit_writeword(rt,(int)&dword);
3289 emit_writeword(r?rth:rt,(int)&dword+4);
3d624f89 3290#else
c43b5311 3291 SysPrintf("STORED_STUB\n");
3d624f89 3292#endif
57871462 3293 }
3294 //emit_pusha();
3295 save_regs(reglist);
97a238a6 3296#ifndef PCSX
57871462 3297 ds=i_regs!=&regs[i];
3298 int real_rs=get_reg(i_regmap,rs1[i]);
3299 u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
3300 if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&0x100f,i);
3301 wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
3302 if(!ds) wb_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs))&~0x100f,i);
97a238a6 3303#endif
57871462 3304 emit_shrimm(rs,16,1);
3305 int cc=get_reg(i_regmap,CCREG);
3306 if(cc<0) {
3307 emit_loadreg(CCREG,2);
3308 }
3309 emit_movimm(ftable,0);
3310 emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
f51dc36c 3311#ifndef PCSX
57871462 3312 emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
f51dc36c 3313#endif
57871462 3314 //emit_readword((int)&last_count,temp);
3315 //emit_addimm(cc,2*stubs[n][5]+2,cc);
3316 //emit_add(cc,temp,cc);
3317 //emit_writeword(cc,(int)&Count);
3318 emit_call((int)&indirect_jump_indexed);
3319 //emit_callreg(rs);
3320 emit_readword((int)&Count,HOST_TEMPREG);
3321 emit_readword((int)&next_interupt,2);
3322 emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG);
3323 emit_writeword(2,(int)&last_count);
3324 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
3325 if(cc<0) {
3326 emit_storereg(CCREG,HOST_TEMPREG);
3327 }
3328 //emit_popa();
3329 restore_regs(reglist);
3330 //if((cc=get_reg(regmap,CCREG))>=0) {
3331 // emit_loadreg(CCREG,cc);
3332 //}
3333 emit_jmp(stubs[n][2]); // return address
b96d3df7 3334#endif // !PCSX
57871462 3335}
3336
3337inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
3338{
3339 int rs=get_reg(regmap,-1);
3340 int rth=get_reg(regmap,target|64);
3341 int rt=get_reg(regmap,target);
3342 assert(rs>=0);
3343 assert(rt>=0);
cbbab9cd 3344#ifdef PCSX
b96d3df7 3345 u_int handler,host_addr=0;
b96d3df7 3346 handler=get_direct_memhandler(mem_wtab,addr,type,&host_addr);
3347 if (handler==0) {
13e35c04 3348 if(addr!=host_addr)
3349 emit_movimm_from(addr,rs,host_addr,rs);
b96d3df7 3350 switch(type) {
3351 case STOREB_STUB: emit_writebyte_indexed(rt,0,rs); break;
3352 case STOREH_STUB: emit_writehword_indexed(rt,0,rs); break;
3353 case STOREW_STUB: emit_writeword_indexed(rt,0,rs); break;
3354 default: assert(0);
3355 }
3356 return;
3357 }
3358
3359 // call a memhandler
3360 save_regs(reglist);
13e35c04 3361 pass_args(rs,rt);
b96d3df7 3362 int cc=get_reg(regmap,CCREG);