Merge pull request #21 from phaseIV/master
[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
c4052f4d 33#ifdef VITA
34char* translation_cache = 0;
35#elif !BASE_ADDR_FIXED
bdeade46 36char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
37#endif
38
4d646738 39#ifndef __MACH__
40#define CALLER_SAVE_REGS 0x100f
41#else
42#define CALLER_SAVE_REGS 0x120f
43#endif
44
57871462 45extern int cycle_count;
46extern int last_count;
47extern int pcaddr;
48extern int pending_exception;
49extern int branch_target;
50extern uint64_t readmem_dword;
3d624f89 51#ifdef MUPEN64
57871462 52extern precomp_instr fake_pc;
3d624f89 53#endif
57871462 54extern void *dynarec_local;
55extern u_int memory_map[1048576];
56extern u_int mini_ht[32][2];
57extern u_int rounding_modes[4];
58
59void indirect_jump_indexed();
60void indirect_jump();
61void do_interrupt();
62void jump_vaddr_r0();
63void jump_vaddr_r1();
64void jump_vaddr_r2();
65void jump_vaddr_r3();
66void jump_vaddr_r4();
67void jump_vaddr_r5();
68void jump_vaddr_r6();
69void jump_vaddr_r7();
70void jump_vaddr_r8();
71void jump_vaddr_r9();
72void jump_vaddr_r10();
73void jump_vaddr_r12();
74
75const u_int jump_vaddr_reg[16] = {
76 (int)jump_vaddr_r0,
77 (int)jump_vaddr_r1,
78 (int)jump_vaddr_r2,
79 (int)jump_vaddr_r3,
80 (int)jump_vaddr_r4,
81 (int)jump_vaddr_r5,
82 (int)jump_vaddr_r6,
83 (int)jump_vaddr_r7,
84 (int)jump_vaddr_r8,
85 (int)jump_vaddr_r9,
86 (int)jump_vaddr_r10,
87 0,
88 (int)jump_vaddr_r12,
89 0,
90 0,
91 0};
92
0bbd1454 93void invalidate_addr_r0();
94void invalidate_addr_r1();
95void invalidate_addr_r2();
96void invalidate_addr_r3();
97void invalidate_addr_r4();
98void invalidate_addr_r5();
99void invalidate_addr_r6();
100void invalidate_addr_r7();
101void invalidate_addr_r8();
102void invalidate_addr_r9();
103void invalidate_addr_r10();
104void invalidate_addr_r12();
105
106const u_int invalidate_addr_reg[16] = {
107 (int)invalidate_addr_r0,
108 (int)invalidate_addr_r1,
109 (int)invalidate_addr_r2,
110 (int)invalidate_addr_r3,
111 (int)invalidate_addr_r4,
112 (int)invalidate_addr_r5,
113 (int)invalidate_addr_r6,
114 (int)invalidate_addr_r7,
115 (int)invalidate_addr_r8,
116 (int)invalidate_addr_r9,
117 (int)invalidate_addr_r10,
118 0,
119 (int)invalidate_addr_r12,
120 0,
121 0,
122 0};
123
57871462 124#include "fpu.h"
125
dd3a91a1 126unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
127
57871462 128/* Linker */
129
130void set_jump_target(int addr,u_int target)
131{
132 u_char *ptr=(u_char *)addr;
133 u_int *ptr2=(u_int *)ptr;
134 if(ptr[3]==0xe2) {
135 assert((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 //printf("target=%x addr=%x insn=%x\n",target,addr,*ptr2);
140 }
141 else if(ptr[3]==0x72) {
142 // generated by emit_jno_unlikely
143 if((target-(u_int)ptr2-8)<1024) {
144 assert((addr&3)==0);
145 assert((target&3)==0);
146 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00;
147 }
148 else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) {
149 assert((addr&3)==0);
150 assert((target&3)==0);
151 *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00;
152 }
153 else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8);
154 }
155 else {
156 assert((ptr[3]&0x0e)==0xa);
157 *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
158 }
159}
160
161// This optionally copies the instruction from the target of the branch into
162// the space before the branch. Works, but the difference in speed is
163// usually insignificant.
164void set_jump_target_fillslot(int addr,u_int target,int copy)
165{
166 u_char *ptr=(u_char *)addr;
167 u_int *ptr2=(u_int *)ptr;
168 assert(!copy||ptr2[-1]==0xe28dd000);
169 if(ptr[3]==0xe2) {
170 assert(!copy);
171 assert((target-(u_int)ptr2-8)<4096);
172 *ptr2=(*ptr2&0xFFFFF000)|(target-(u_int)ptr2-8);
173 }
174 else {
175 assert((ptr[3]&0x0e)==0xa);
176 u_int target_insn=*(u_int *)target;
177 if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags
178 copy=0;
179 }
180 if((target_insn&0x0c100000)==0x04100000) { // Load
181 copy=0;
182 }
183 if(target_insn&0x08000000) {
184 copy=0;
185 }
186 if(copy) {
187 ptr2[-1]=target_insn;
188 target+=4;
189 }
190 *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8);
191 }
192}
193
194/* Literal pool */
195add_literal(int addr,int val)
196{
15776b68 197 assert(literalcount<sizeof(literals)/sizeof(literals[0]));
57871462 198 literals[literalcount][0]=addr;
199 literals[literalcount][1]=val;
200 literalcount++;
201}
202
f76eeef9 203void *kill_pointer(void *stub)
57871462 204{
205 int *ptr=(int *)(stub+4);
206 assert((*ptr&0x0ff00000)==0x05900000);
207 u_int offset=*ptr&0xfff;
208 int **l_ptr=(void *)ptr+offset+8;
209 int *i_ptr=*l_ptr;
210 set_jump_target((int)i_ptr,(int)stub);
f76eeef9 211 return i_ptr;
57871462 212}
213
f968d35d 214// find where external branch is liked to using addr of it's stub:
215// get address that insn one after stub loads (dyna_linker arg1),
216// treat it as a pointer to branch insn,
217// return addr where that branch jumps to
57871462 218int get_pointer(void *stub)
219{
220 //printf("get_pointer(%x)\n",(int)stub);
221 int *ptr=(int *)(stub+4);
f968d35d 222 assert((*ptr&0x0fff0000)==0x059f0000);
57871462 223 u_int offset=*ptr&0xfff;
224 int **l_ptr=(void *)ptr+offset+8;
225 int *i_ptr=*l_ptr;
226 assert((*i_ptr&0x0f000000)==0x0a000000);
227 return (int)i_ptr+((*i_ptr<<8)>>6)+8;
228}
229
230// Find the "clean" entry point from a "dirty" entry point
231// by skipping past the call to verify_code
232u_int get_clean_addr(int addr)
233{
234 int *ptr=(int *)addr;
665f33e1 235 #ifndef HAVE_ARMV7
57871462 236 ptr+=4;
237 #else
238 ptr+=6;
239 #endif
240 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
241 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
242 ptr++;
243 if((*ptr&0xFF000000)==0xea000000) {
244 return (int)ptr+((*ptr<<8)>>6)+8; // follow jump
245 }
246 return (u_int)ptr;
247}
248
249int verify_dirty(int addr)
250{
251 u_int *ptr=(u_int *)addr;
665f33e1 252 #ifndef HAVE_ARMV7
57871462 253 // get from literal pool
15776b68 254 assert((*ptr&0xFFFF0000)==0xe59f0000);
57871462 255 u_int offset=*ptr&0xfff;
256 u_int *l_ptr=(void *)ptr+offset+8;
257 u_int source=l_ptr[0];
258 u_int copy=l_ptr[1];
259 u_int len=l_ptr[2];
260 ptr+=4;
261 #else
262 // ARMv7 movw/movt
263 assert((*ptr&0xFFF00000)==0xe3000000);
264 u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
265 u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
266 u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
267 ptr+=6;
268 #endif
269 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
270 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
63cb0298 271#ifndef DISABLE_TLB
cfcba99a 272 u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl
57871462 273 if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) {
274 unsigned int page=source>>12;
275 unsigned int map_value=memory_map[page];
276 if(map_value>=0x80000000) return 0;
277 while(page<((source+len-1)>>12)) {
278 if((memory_map[++page]<<2)!=(map_value<<2)) return 0;
279 }
280 source = source+(map_value<<2);
281 }
63cb0298 282#endif
57871462 283 //printf("verify_dirty: %x %x %x\n",source,copy,len);
284 return !memcmp((void *)source,(void *)copy,len);
285}
286
287// This doesn't necessarily find all clean entry points, just
288// guarantees that it's not dirty
289int isclean(int addr)
290{
665f33e1 291 #ifndef HAVE_ARMV7
57871462 292 int *ptr=((u_int *)addr)+4;
293 #else
294 int *ptr=((u_int *)addr)+6;
295 #endif
296 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
297 if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction
298 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0;
299 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_vm) return 0;
300 if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_ds) return 0;
301 return 1;
302}
303
4a35de07 304// get source that block at addr was compiled from (host pointers)
57871462 305void get_bounds(int addr,u_int *start,u_int *end)
306{
307 u_int *ptr=(u_int *)addr;
665f33e1 308 #ifndef HAVE_ARMV7
57871462 309 // get from literal pool
15776b68 310 assert((*ptr&0xFFFF0000)==0xe59f0000);
57871462 311 u_int offset=*ptr&0xfff;
312 u_int *l_ptr=(void *)ptr+offset+8;
313 u_int source=l_ptr[0];
314 //u_int copy=l_ptr[1];
315 u_int len=l_ptr[2];
316 ptr+=4;
317 #else
318 // ARMv7 movw/movt
319 assert((*ptr&0xFFF00000)==0xe3000000);
320 u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000);
321 //u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000);
322 u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000);
323 ptr+=6;
324 #endif
325 if((*ptr&0xFF000000)!=0xeb000000) ptr++;
326 assert((*ptr&0xFF000000)==0xeb000000); // bl instruction
63cb0298 327#ifndef DISABLE_TLB
cfcba99a 328 u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl
57871462 329 if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) {
330 if(memory_map[source>>12]>=0x80000000) source = 0;
331 else source = source+(memory_map[source>>12]<<2);
332 }
63cb0298 333#endif
57871462 334 *start=source;
335 *end=source+len;
336}
337
338/* Register allocation */
339
340// Note: registers are allocated clean (unmodified state)
341// if you intend to modify the register, you must call dirty_reg().
342void alloc_reg(struct regstat *cur,int i,signed char reg)
343{
344 int r,hr;
345 int preferred_reg = (reg&7);
346 if(reg==CCREG) preferred_reg=HOST_CCREG;
347 if(reg==PTEMP||reg==FTEMP) preferred_reg=12;
348
349 // Don't allocate unused registers
350 if((cur->u>>reg)&1) return;
351
352 // see if it's already allocated
353 for(hr=0;hr<HOST_REGS;hr++)
354 {
355 if(cur->regmap[hr]==reg) return;
356 }
357
358 // Keep the same mapping if the register was already allocated in a loop
359 preferred_reg = loop_reg(i,reg,preferred_reg);
360
361 // Try to allocate the preferred register
362 if(cur->regmap[preferred_reg]==-1) {
363 cur->regmap[preferred_reg]=reg;
364 cur->dirty&=~(1<<preferred_reg);
365 cur->isconst&=~(1<<preferred_reg);
366 return;
367 }
368 r=cur->regmap[preferred_reg];
369 if(r<64&&((cur->u>>r)&1)) {
370 cur->regmap[preferred_reg]=reg;
371 cur->dirty&=~(1<<preferred_reg);
372 cur->isconst&=~(1<<preferred_reg);
373 return;
374 }
375 if(r>=64&&((cur->uu>>(r&63))&1)) {
376 cur->regmap[preferred_reg]=reg;
377 cur->dirty&=~(1<<preferred_reg);
378 cur->isconst&=~(1<<preferred_reg);
379 return;
380 }
381
382 // Clear any unneeded registers
383 // We try to keep the mapping consistent, if possible, because it
384 // makes branches easier (especially loops). So we try to allocate
385 // first (see above) before removing old mappings. If this is not
386 // possible then go ahead and clear out the registers that are no
387 // longer needed.
388 for(hr=0;hr<HOST_REGS;hr++)
389 {
390 r=cur->regmap[hr];
391 if(r>=0) {
392 if(r<64) {
393 if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
394 }
395 else
396 {
397 if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;}
398 }
399 }
400 }
401 // Try to allocate any available register, but prefer
402 // registers that have not been used recently.
403 if(i>0) {
404 for(hr=0;hr<HOST_REGS;hr++) {
405 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
406 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]) {
407 cur->regmap[hr]=reg;
408 cur->dirty&=~(1<<hr);
409 cur->isconst&=~(1<<hr);
410 return;
411 }
412 }
413 }
414 }
415 // Try to allocate any available register
416 for(hr=0;hr<HOST_REGS;hr++) {
417 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
418 cur->regmap[hr]=reg;
419 cur->dirty&=~(1<<hr);
420 cur->isconst&=~(1<<hr);
421 return;
422 }
423 }
424
425 // Ok, now we have to evict someone
426 // Pick a register we hopefully won't need soon
427 u_char hsn[MAXREG+1];
428 memset(hsn,10,sizeof(hsn));
429 int j;
430 lsn(hsn,i,&preferred_reg);
431 //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]);
432 //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]);
433 if(i>0) {
434 // Don't evict the cycle count at entry points, otherwise the entry
435 // stub will have to write it.
436 if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
437 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;
438 for(j=10;j>=3;j--)
439 {
440 // Alloc preferred register if available
441 if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
442 for(hr=0;hr<HOST_REGS;hr++) {
443 // Evict both parts of a 64-bit register
444 if((cur->regmap[hr]&63)==r) {
445 cur->regmap[hr]=-1;
446 cur->dirty&=~(1<<hr);
447 cur->isconst&=~(1<<hr);
448 }
449 }
450 cur->regmap[preferred_reg]=reg;
451 return;
452 }
453 for(r=1;r<=MAXREG;r++)
454 {
455 if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
456 for(hr=0;hr<HOST_REGS;hr++) {
457 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
458 if(cur->regmap[hr]==r+64) {
459 cur->regmap[hr]=reg;
460 cur->dirty&=~(1<<hr);
461 cur->isconst&=~(1<<hr);
462 return;
463 }
464 }
465 }
466 for(hr=0;hr<HOST_REGS;hr++) {
467 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
468 if(cur->regmap[hr]==r) {
469 cur->regmap[hr]=reg;
470 cur->dirty&=~(1<<hr);
471 cur->isconst&=~(1<<hr);
472 return;
473 }
474 }
475 }
476 }
477 }
478 }
479 }
480 for(j=10;j>=0;j--)
481 {
482 for(r=1;r<=MAXREG;r++)
483 {
484 if(hsn[r]==j) {
485 for(hr=0;hr<HOST_REGS;hr++) {
486 if(cur->regmap[hr]==r+64) {
487 cur->regmap[hr]=reg;
488 cur->dirty&=~(1<<hr);
489 cur->isconst&=~(1<<hr);
490 return;
491 }
492 }
493 for(hr=0;hr<HOST_REGS;hr++) {
494 if(cur->regmap[hr]==r) {
495 cur->regmap[hr]=reg;
496 cur->dirty&=~(1<<hr);
497 cur->isconst&=~(1<<hr);
498 return;
499 }
500 }
501 }
502 }
503 }
c43b5311 504 SysPrintf("This shouldn't happen (alloc_reg)");exit(1);
57871462 505}
506
507void alloc_reg64(struct regstat *cur,int i,signed char reg)
508{
509 int preferred_reg = 8+(reg&1);
510 int r,hr;
511
512 // allocate the lower 32 bits
513 alloc_reg(cur,i,reg);
514
515 // Don't allocate unused registers
516 if((cur->uu>>reg)&1) return;
517
518 // see if the upper half is already allocated
519 for(hr=0;hr<HOST_REGS;hr++)
520 {
521 if(cur->regmap[hr]==reg+64) return;
522 }
523
524 // Keep the same mapping if the register was already allocated in a loop
525 preferred_reg = loop_reg(i,reg,preferred_reg);
526
527 // Try to allocate the preferred register
528 if(cur->regmap[preferred_reg]==-1) {
529 cur->regmap[preferred_reg]=reg|64;
530 cur->dirty&=~(1<<preferred_reg);
531 cur->isconst&=~(1<<preferred_reg);
532 return;
533 }
534 r=cur->regmap[preferred_reg];
535 if(r<64&&((cur->u>>r)&1)) {
536 cur->regmap[preferred_reg]=reg|64;
537 cur->dirty&=~(1<<preferred_reg);
538 cur->isconst&=~(1<<preferred_reg);
539 return;
540 }
541 if(r>=64&&((cur->uu>>(r&63))&1)) {
542 cur->regmap[preferred_reg]=reg|64;
543 cur->dirty&=~(1<<preferred_reg);
544 cur->isconst&=~(1<<preferred_reg);
545 return;
546 }
547
548 // Clear any unneeded registers
549 // We try to keep the mapping consistent, if possible, because it
550 // makes branches easier (especially loops). So we try to allocate
551 // first (see above) before removing old mappings. If this is not
552 // possible then go ahead and clear out the registers that are no
553 // longer needed.
554 for(hr=HOST_REGS-1;hr>=0;hr--)
555 {
556 r=cur->regmap[hr];
557 if(r>=0) {
558 if(r<64) {
559 if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
560 }
561 else
562 {
563 if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;}
564 }
565 }
566 }
567 // Try to allocate any available register, but prefer
568 // registers that have not been used recently.
569 if(i>0) {
570 for(hr=0;hr<HOST_REGS;hr++) {
571 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
572 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]) {
573 cur->regmap[hr]=reg|64;
574 cur->dirty&=~(1<<hr);
575 cur->isconst&=~(1<<hr);
576 return;
577 }
578 }
579 }
580 }
581 // Try to allocate any available register
582 for(hr=0;hr<HOST_REGS;hr++) {
583 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
584 cur->regmap[hr]=reg|64;
585 cur->dirty&=~(1<<hr);
586 cur->isconst&=~(1<<hr);
587 return;
588 }
589 }
590
591 // Ok, now we have to evict someone
592 // Pick a register we hopefully won't need soon
593 u_char hsn[MAXREG+1];
594 memset(hsn,10,sizeof(hsn));
595 int j;
596 lsn(hsn,i,&preferred_reg);
597 //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]);
598 //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]);
599 if(i>0) {
600 // Don't evict the cycle count at entry points, otherwise the entry
601 // stub will have to write it.
602 if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
603 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;
604 for(j=10;j>=3;j--)
605 {
606 // Alloc preferred register if available
607 if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
608 for(hr=0;hr<HOST_REGS;hr++) {
609 // Evict both parts of a 64-bit register
610 if((cur->regmap[hr]&63)==r) {
611 cur->regmap[hr]=-1;
612 cur->dirty&=~(1<<hr);
613 cur->isconst&=~(1<<hr);
614 }
615 }
616 cur->regmap[preferred_reg]=reg|64;
617 return;
618 }
619 for(r=1;r<=MAXREG;r++)
620 {
621 if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
622 for(hr=0;hr<HOST_REGS;hr++) {
623 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
624 if(cur->regmap[hr]==r+64) {
625 cur->regmap[hr]=reg|64;
626 cur->dirty&=~(1<<hr);
627 cur->isconst&=~(1<<hr);
628 return;
629 }
630 }
631 }
632 for(hr=0;hr<HOST_REGS;hr++) {
633 if(hr!=HOST_CCREG||j<hsn[CCREG]) {
634 if(cur->regmap[hr]==r) {
635 cur->regmap[hr]=reg|64;
636 cur->dirty&=~(1<<hr);
637 cur->isconst&=~(1<<hr);
638 return;
639 }
640 }
641 }
642 }
643 }
644 }
645 }
646 for(j=10;j>=0;j--)
647 {
648 for(r=1;r<=MAXREG;r++)
649 {
650 if(hsn[r]==j) {
651 for(hr=0;hr<HOST_REGS;hr++) {
652 if(cur->regmap[hr]==r+64) {
653 cur->regmap[hr]=reg|64;
654 cur->dirty&=~(1<<hr);
655 cur->isconst&=~(1<<hr);
656 return;
657 }
658 }
659 for(hr=0;hr<HOST_REGS;hr++) {
660 if(cur->regmap[hr]==r) {
661 cur->regmap[hr]=reg|64;
662 cur->dirty&=~(1<<hr);
663 cur->isconst&=~(1<<hr);
664 return;
665 }
666 }
667 }
668 }
669 }
c43b5311 670 SysPrintf("This shouldn't happen");exit(1);
57871462 671}
672
673// Allocate a temporary register. This is done without regard to
674// dirty status or whether the register we request is on the unneeded list
675// Note: This will only allocate one register, even if called multiple times
676void alloc_reg_temp(struct regstat *cur,int i,signed char reg)
677{
678 int r,hr;
679 int preferred_reg = -1;
680
681 // see if it's already allocated
682 for(hr=0;hr<HOST_REGS;hr++)
683 {
684 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==reg) return;
685 }
686
687 // Try to allocate any available register
688 for(hr=HOST_REGS-1;hr>=0;hr--) {
689 if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
690 cur->regmap[hr]=reg;
691 cur->dirty&=~(1<<hr);
692 cur->isconst&=~(1<<hr);
693 return;
694 }
695 }
696
697 // Find an unneeded register
698 for(hr=HOST_REGS-1;hr>=0;hr--)
699 {
700 r=cur->regmap[hr];
701 if(r>=0) {
702 if(r<64) {
703 if((cur->u>>r)&1) {
704 if(i==0||((unneeded_reg[i-1]>>r)&1)) {
705 cur->regmap[hr]=reg;
706 cur->dirty&=~(1<<hr);
707 cur->isconst&=~(1<<hr);
708 return;
709 }
710 }
711 }
712 else
713 {
714 if((cur->uu>>(r&63))&1) {
715 if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) {
716 cur->regmap[hr]=reg;
717 cur->dirty&=~(1<<hr);
718 cur->isconst&=~(1<<hr);
719 return;
720 }
721 }
722 }
723 }
724 }
725
726 // Ok, now we have to evict someone
727 // Pick a register we hopefully won't need soon
728 // TODO: we might want to follow unconditional jumps here
729 // TODO: get rid of dupe code and make this into a function
730 u_char hsn[MAXREG+1];
731 memset(hsn,10,sizeof(hsn));
732 int j;
733 lsn(hsn,i,&preferred_reg);
734 //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]);
735 if(i>0) {
736 // Don't evict the cycle count at entry points, otherwise the entry
737 // stub will have to write it.
738 if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
739 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;
740 for(j=10;j>=3;j--)
741 {
742 for(r=1;r<=MAXREG;r++)
743 {
744 if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
745 for(hr=0;hr<HOST_REGS;hr++) {
746 if(hr!=HOST_CCREG||hsn[CCREG]>2) {
747 if(cur->regmap[hr]==r+64) {
748 cur->regmap[hr]=reg;
749 cur->dirty&=~(1<<hr);
750 cur->isconst&=~(1<<hr);
751 return;
752 }
753 }
754 }
755 for(hr=0;hr<HOST_REGS;hr++) {
756 if(hr!=HOST_CCREG||hsn[CCREG]>2) {
757 if(cur->regmap[hr]==r) {
758 cur->regmap[hr]=reg;
759 cur->dirty&=~(1<<hr);
760 cur->isconst&=~(1<<hr);
761 return;
762 }
763 }
764 }
765 }
766 }
767 }
768 }
769 for(j=10;j>=0;j--)
770 {
771 for(r=1;r<=MAXREG;r++)
772 {
773 if(hsn[r]==j) {
774 for(hr=0;hr<HOST_REGS;hr++) {
775 if(cur->regmap[hr]==r+64) {
776 cur->regmap[hr]=reg;
777 cur->dirty&=~(1<<hr);
778 cur->isconst&=~(1<<hr);
779 return;
780 }
781 }
782 for(hr=0;hr<HOST_REGS;hr++) {
783 if(cur->regmap[hr]==r) {
784 cur->regmap[hr]=reg;
785 cur->dirty&=~(1<<hr);
786 cur->isconst&=~(1<<hr);
787 return;
788 }
789 }
790 }
791 }
792 }
c43b5311 793 SysPrintf("This shouldn't happen");exit(1);
57871462 794}
795// Allocate a specific ARM register.
796void alloc_arm_reg(struct regstat *cur,int i,signed char reg,char hr)
797{
798 int n;
f776eb14 799 int dirty=0;
57871462 800
801 // see if it's already allocated (and dealloc it)
802 for(n=0;n<HOST_REGS;n++)
803 {
f776eb14 804 if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
805 dirty=(cur->dirty>>n)&1;
806 cur->regmap[n]=-1;
807 }
57871462 808 }
809
810 cur->regmap[hr]=reg;
811 cur->dirty&=~(1<<hr);
f776eb14 812 cur->dirty|=dirty<<hr;
57871462 813 cur->isconst&=~(1<<hr);
814}
815
816// Alloc cycle count into dedicated register
817alloc_cc(struct regstat *cur,int i)
818{
819 alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
820}
821
822/* Special alloc */
823
824
825/* Assembler */
826
827char regname[16][4] = {
828 "r0",
829 "r1",
830 "r2",
831 "r3",
832 "r4",
833 "r5",
834 "r6",
835 "r7",
836 "r8",
837 "r9",
838 "r10",
839 "fp",
840 "r12",
841 "sp",
842 "lr",
843 "pc"};
844
845void output_byte(u_char byte)
846{
847 *(out++)=byte;
848}
849void output_modrm(u_char mod,u_char rm,u_char ext)
850{
851 assert(mod<4);
852 assert(rm<8);
853 assert(ext<8);
854 u_char byte=(mod<<6)|(ext<<3)|rm;
855 *(out++)=byte;
856}
857void output_sib(u_char scale,u_char index,u_char base)
858{
859 assert(scale<4);
860 assert(index<8);
861 assert(base<8);
862 u_char byte=(scale<<6)|(index<<3)|base;
863 *(out++)=byte;
864}
865void output_w32(u_int word)
866{
867 *((u_int *)out)=word;
868 out+=4;
869}
870u_int rd_rn_rm(u_int rd, u_int rn, u_int rm)
871{
872 assert(rd<16);
873 assert(rn<16);
874 assert(rm<16);
875 return((rn<<16)|(rd<<12)|rm);
876}
877u_int rd_rn_imm_shift(u_int rd, u_int rn, u_int imm, u_int shift)
878{
879 assert(rd<16);
880 assert(rn<16);
881 assert(imm<256);
882 assert((shift&1)==0);
883 return((rn<<16)|(rd<<12)|(((32-shift)&30)<<7)|imm);
884}
885u_int genimm(u_int imm,u_int *encoded)
886{
c2e3bd42 887 *encoded=0;
888 if(imm==0) return 1;
57871462 889 int i=32;
890 while(i>0)
891 {
892 if(imm<256) {
893 *encoded=((i&30)<<7)|imm;
894 return 1;
895 }
896 imm=(imm>>2)|(imm<<30);i-=2;
897 }
898 return 0;
899}
cfbd3c6e 900void genimm_checked(u_int imm,u_int *encoded)
901{
902 u_int ret=genimm(imm,encoded);
903 assert(ret);
904}
57871462 905u_int genjmp(u_int addr)
906{
907 int offset=addr-(int)out-8;
e80343e2 908 if(offset<-33554432||offset>=33554432) {
909 if (addr>2) {
c43b5311 910 SysPrintf("genjmp: out of range: %08x\n", offset);
e80343e2 911 exit(1);
912 }
913 return 0;
914 }
57871462 915 return ((u_int)offset>>2)&0xffffff;
916}
917
918void emit_mov(int rs,int rt)
919{
920 assem_debug("mov %s,%s\n",regname[rt],regname[rs]);
921 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs));
922}
923
924void emit_movs(int rs,int rt)
925{
926 assem_debug("movs %s,%s\n",regname[rt],regname[rs]);
927 output_w32(0xe1b00000|rd_rn_rm(rt,0,rs));
928}
929
930void emit_add(int rs1,int rs2,int rt)
931{
932 assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
933 output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2));
934}
935
936void emit_adds(int rs1,int rs2,int rt)
937{
938 assem_debug("adds %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
939 output_w32(0xe0900000|rd_rn_rm(rt,rs1,rs2));
940}
941
942void emit_adcs(int rs1,int rs2,int rt)
943{
944 assem_debug("adcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
945 output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2));
946}
947
948void emit_sbc(int rs1,int rs2,int rt)
949{
950 assem_debug("sbc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
951 output_w32(0xe0c00000|rd_rn_rm(rt,rs1,rs2));
952}
953
954void emit_sbcs(int rs1,int rs2,int rt)
955{
956 assem_debug("sbcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
957 output_w32(0xe0d00000|rd_rn_rm(rt,rs1,rs2));
958}
959
960void emit_neg(int rs, int rt)
961{
962 assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
963 output_w32(0xe2600000|rd_rn_rm(rt,rs,0));
964}
965
966void emit_negs(int rs, int rt)
967{
968 assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]);
969 output_w32(0xe2700000|rd_rn_rm(rt,rs,0));
970}
971
972void emit_sub(int rs1,int rs2,int rt)
973{
974 assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
975 output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2));
976}
977
978void emit_subs(int rs1,int rs2,int rt)
979{
980 assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
981 output_w32(0xe0500000|rd_rn_rm(rt,rs1,rs2));
982}
983
984void emit_zeroreg(int rt)
985{
986 assem_debug("mov %s,#0\n",regname[rt]);
987 output_w32(0xe3a00000|rd_rn_rm(rt,0,0));
988}
989
790ee18e 990void emit_loadlp(u_int imm,u_int rt)
991{
992 add_literal((int)out,imm);
993 assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm);
994 output_w32(0xe5900000|rd_rn_rm(rt,15,0));
995}
996void emit_movw(u_int imm,u_int rt)
997{
998 assert(imm<65536);
999 assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
1000 output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000));
1001}
1002void emit_movt(u_int imm,u_int rt)
1003{
1004 assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
1005 output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000));
1006}
1007void emit_movimm(u_int imm,u_int rt)
1008{
1009 u_int armval;
1010 if(genimm(imm,&armval)) {
1011 assem_debug("mov %s,#%d\n",regname[rt],imm);
1012 output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
1013 }else if(genimm(~imm,&armval)) {
1014 assem_debug("mvn %s,#%d\n",regname[rt],imm);
1015 output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
1016 }else if(imm<65536) {
665f33e1 1017 #ifndef HAVE_ARMV7
790ee18e 1018 assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00);
1019 output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8));
1020 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
1021 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1022 #else
1023 emit_movw(imm,rt);
1024 #endif
1025 }else{
665f33e1 1026 #ifndef HAVE_ARMV7
790ee18e 1027 emit_loadlp(imm,rt);
1028 #else
1029 emit_movw(imm&0x0000FFFF,rt);
1030 emit_movt(imm&0xFFFF0000,rt);
1031 #endif
1032 }
1033}
1034void emit_pcreladdr(u_int rt)
1035{
1036 assem_debug("add %s,pc,#?\n",regname[rt]);
1037 output_w32(0xe2800000|rd_rn_rm(rt,15,0));
1038}
1039
57871462 1040void emit_loadreg(int r, int hr)
1041{
3d624f89 1042#ifdef FORCE32
1043 if(r&64) {
c43b5311 1044 SysPrintf("64bit load in 32bit mode!\n");
7f2607ea 1045 assert(0);
1046 return;
3d624f89 1047 }
1048#endif
57871462 1049 if((r&63)==0)
1050 emit_zeroreg(hr);
1051 else {
3d624f89 1052 int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
57871462 1053 if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4);
1054 if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4);
1055 if(r==CCREG) addr=(int)&cycle_count;
1056 if(r==CSREG) addr=(int)&Status;
1057 if(r==FSREG) addr=(int)&FCR31;
1058 if(r==INVCP) addr=(int)&invc_ptr;
1059 u_int offset = addr-(u_int)&dynarec_local;
1060 assert(offset<4096);
1061 assem_debug("ldr %s,fp+%d\n",regname[hr],offset);
1062 output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset);
1063 }
1064}
1065void emit_storereg(int r, int hr)
1066{
3d624f89 1067#ifdef FORCE32
1068 if(r&64) {
c43b5311 1069 SysPrintf("64bit store in 32bit mode!\n");
7f2607ea 1070 assert(0);
1071 return;
3d624f89 1072 }
1073#endif
1074 int addr=((int)reg)+((r&63)<<REG_SHIFT)+((r&64)>>4);
57871462 1075 if((r&63)==HIREG) addr=(int)&hi+((r&64)>>4);
1076 if((r&63)==LOREG) addr=(int)&lo+((r&64)>>4);
1077 if(r==CCREG) addr=(int)&cycle_count;
1078 if(r==FSREG) addr=(int)&FCR31;
1079 u_int offset = addr-(u_int)&dynarec_local;
1080 assert(offset<4096);
1081 assem_debug("str %s,fp+%d\n",regname[hr],offset);
1082 output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset);
1083}
1084
1085void emit_test(int rs, int rt)
1086{
1087 assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
1088 output_w32(0xe1100000|rd_rn_rm(0,rs,rt));
1089}
1090
1091void emit_testimm(int rs,int imm)
1092{
1093 u_int armval;
5a05d80c 1094 assem_debug("tst %s,#%d\n",regname[rs],imm);
cfbd3c6e 1095 genimm_checked(imm,&armval);
57871462 1096 output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval);
1097}
1098
b9b61529 1099void emit_testeqimm(int rs,int imm)
1100{
1101 u_int armval;
1102 assem_debug("tsteq %s,$%d\n",regname[rs],imm);
cfbd3c6e 1103 genimm_checked(imm,&armval);
b9b61529 1104 output_w32(0x03100000|rd_rn_rm(0,rs,0)|armval);
1105}
1106
57871462 1107void emit_not(int rs,int rt)
1108{
1109 assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
1110 output_w32(0xe1e00000|rd_rn_rm(rt,0,rs));
1111}
1112
b9b61529 1113void emit_mvnmi(int rs,int rt)
1114{
1115 assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
1116 output_w32(0x41e00000|rd_rn_rm(rt,0,rs));
1117}
1118
57871462 1119void emit_and(u_int rs1,u_int rs2,u_int rt)
1120{
1121 assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1122 output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2));
1123}
1124
1125void emit_or(u_int rs1,u_int rs2,u_int rt)
1126{
1127 assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1128 output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2));
1129}
1130void emit_or_and_set_flags(int rs1,int rs2,int rt)
1131{
1132 assem_debug("orrs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1133 output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2));
1134}
1135
f70d384d 1136void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
1137{
1138 assert(rs<16);
1139 assert(rt<16);
1140 assert(imm<32);
1141 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
1142 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|(imm<<7));
1143}
1144
576bbd8f 1145void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
1146{
1147 assert(rs<16);
1148 assert(rt<16);
1149 assert(imm<32);
1150 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
1151 output_w32(0xe1800020|rd_rn_rm(rt,rt,rs)|(imm<<7));
1152}
1153
57871462 1154void emit_xor(u_int rs1,u_int rs2,u_int rt)
1155{
1156 assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1157 output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2));
1158}
1159
57871462 1160void emit_addimm(u_int rs,int imm,u_int rt)
1161{
1162 assert(rs<16);
1163 assert(rt<16);
1164 if(imm!=0) {
57871462 1165 u_int armval;
1166 if(genimm(imm,&armval)) {
1167 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm);
1168 output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
1169 }else if(genimm(-imm,&armval)) {
8a0a8423 1170 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-imm);
57871462 1171 output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
1172 }else if(imm<0) {
ffb0b9e0 1173 assert(imm>-65536);
57871462 1174 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00);
1175 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
1176 output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8));
1177 output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
1178 }else{
ffb0b9e0 1179 assert(imm<65536);
57871462 1180 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
1181 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
1182 output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8));
1183 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1184 }
1185 }
1186 else if(rs!=rt) emit_mov(rs,rt);
1187}
1188
1189void emit_addimm_and_set_flags(int imm,int rt)
1190{
1191 assert(imm>-65536&&imm<65536);
1192 u_int armval;
1193 if(genimm(imm,&armval)) {
1194 assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm);
1195 output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval);
1196 }else if(genimm(-imm,&armval)) {
1197 assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],imm);
1198 output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval);
1199 }else if(imm<0) {
1200 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF00);
1201 assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF);
1202 output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8));
1203 output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0));
1204 }else{
1205 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF00);
1206 assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF);
1207 output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8));
1208 output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1209 }
1210}
1211void emit_addimm_no_flags(u_int imm,u_int rt)
1212{
1213 emit_addimm(rt,imm,rt);
1214}
1215
1216void emit_addnop(u_int r)
1217{
1218 assert(r<16);
1219 assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]);
1220 output_w32(0xe2800000|rd_rn_rm(r,r,0));
1221}
1222
1223void emit_adcimm(u_int rs,int imm,u_int rt)
1224{
1225 u_int armval;
cfbd3c6e 1226 genimm_checked(imm,&armval);
57871462 1227 assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm);
1228 output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval);
1229}
1230/*void emit_sbcimm(int imm,u_int rt)
1231{
1232 u_int armval;
cfbd3c6e 1233 genimm_checked(imm,&armval);
57871462 1234 assem_debug("sbc %s,%s,#%d\n",regname[rt],regname[rt],imm);
1235 output_w32(0xe2c00000|rd_rn_rm(rt,rt,0)|armval);
1236}*/
1237void emit_sbbimm(int imm,u_int rt)
1238{
1239 assem_debug("sbb $%d,%%%s\n",imm,regname[rt]);
1240 assert(rt<8);
1241 if(imm<128&&imm>=-128) {
1242 output_byte(0x83);
1243 output_modrm(3,rt,3);
1244 output_byte(imm);
1245 }
1246 else
1247 {
1248 output_byte(0x81);
1249 output_modrm(3,rt,3);
1250 output_w32(imm);
1251 }
1252}
1253void emit_rscimm(int rs,int imm,u_int rt)
1254{
1255 assert(0);
1256 u_int armval;
cfbd3c6e 1257 genimm_checked(imm,&armval);
57871462 1258 assem_debug("rsc %s,%s,#%d\n",regname[rt],regname[rs],imm);
1259 output_w32(0xe2e00000|rd_rn_rm(rt,rs,0)|armval);
1260}
1261
1262void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl)
1263{
1264 // TODO: if(genimm(imm,&armval)) ...
1265 // else
1266 emit_movimm(imm,HOST_TEMPREG);
1267 emit_adds(HOST_TEMPREG,rsl,rtl);
1268 emit_adcimm(rsh,0,rth);
1269}
1270
1271void emit_sbb(int rs1,int rs2)
1272{
1273 assem_debug("sbb %%%s,%%%s\n",regname[rs2],regname[rs1]);
1274 output_byte(0x19);
1275 output_modrm(3,rs1,rs2);
1276}
1277
1278void emit_andimm(int rs,int imm,int rt)
1279{
1280 u_int armval;
790ee18e 1281 if(imm==0) {
1282 emit_zeroreg(rt);
1283 }else if(genimm(imm,&armval)) {
57871462 1284 assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm);
1285 output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval);
1286 }else if(genimm(~imm,&armval)) {
1287 assem_debug("bic %s,%s,#%d\n",regname[rt],regname[rs],imm);
1288 output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval);
1289 }else if(imm==65535) {
332a4533 1290 #ifndef HAVE_ARMV6
57871462 1291 assem_debug("bic %s,%s,#FF000000\n",regname[rt],regname[rs]);
1292 output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF);
1293 assem_debug("bic %s,%s,#00FF0000\n",regname[rt],regname[rt]);
1294 output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF);
1295 #else
1296 assem_debug("uxth %s,%s\n",regname[rt],regname[rs]);
1297 output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs));
1298 #endif
1299 }else{
1300 assert(imm>0&&imm<65535);
665f33e1 1301 #ifndef HAVE_ARMV7
57871462 1302 assem_debug("mov r14,#%d\n",imm&0xFF00);
1303 output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8));
1304 assem_debug("add r14,r14,#%d\n",imm&0xFF);
1305 output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0));
1306 #else
1307 emit_movw(imm,HOST_TEMPREG);
1308 #endif
1309 assem_debug("and %s,%s,r14\n",regname[rt],regname[rs]);
1310 output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG));
1311 }
1312}
1313
1314void emit_orimm(int rs,int imm,int rt)
1315{
1316 u_int armval;
790ee18e 1317 if(imm==0) {
1318 if(rs!=rt) emit_mov(rs,rt);
1319 }else if(genimm(imm,&armval)) {
57871462 1320 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1321 output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval);
1322 }else{
1323 assert(imm>0&&imm<65536);
1324 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
1325 assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
1326 output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8));
1327 output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1328 }
1329}
1330
1331void emit_xorimm(int rs,int imm,int rt)
1332{
57871462 1333 u_int armval;
790ee18e 1334 if(imm==0) {
1335 if(rs!=rt) emit_mov(rs,rt);
1336 }else if(genimm(imm,&armval)) {
57871462 1337 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm);
1338 output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval);
1339 }else{
514ed0d9 1340 assert(imm>0&&imm<65536);
57871462 1341 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00);
1342 assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF);
1343 output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8));
1344 output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0));
1345 }
1346}
1347
1348void emit_shlimm(int rs,u_int imm,int rt)
1349{
1350 assert(imm>0);
1351 assert(imm<32);
1352 //if(imm==1) ...
1353 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
1354 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1355}
1356
c6c3b1b3 1357void emit_lsls_imm(int rs,int imm,int rt)
1358{
1359 assert(imm>0);
1360 assert(imm<32);
1361 assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
1362 output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1363}
1364
665f33e1 1365void emit_lslpls_imm(int rs,int imm,int rt)
1366{
1367 assert(imm>0);
1368 assert(imm<32);
1369 assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
1370 output_w32(0x51b00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1371}
1372
57871462 1373void emit_shrimm(int rs,u_int imm,int rt)
1374{
1375 assert(imm>0);
1376 assert(imm<32);
1377 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1378 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
1379}
1380
1381void emit_sarimm(int rs,u_int imm,int rt)
1382{
1383 assert(imm>0);
1384 assert(imm<32);
1385 assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1386 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7));
1387}
1388
1389void emit_rorimm(int rs,u_int imm,int rt)
1390{
1391 assert(imm>0);
1392 assert(imm<32);
1393 assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
1394 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7));
1395}
1396
1397void emit_shldimm(int rs,int rs2,u_int imm,int rt)
1398{
1399 assem_debug("shld %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm);
1400 assert(imm>0);
1401 assert(imm<32);
1402 //if(imm==1) ...
1403 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
1404 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7));
1405 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs2],32-imm);
1406 output_w32(0xe1800020|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7));
1407}
1408
1409void emit_shrdimm(int rs,int rs2,u_int imm,int rt)
1410{
1411 assem_debug("shrd %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm);
1412 assert(imm>0);
1413 assert(imm<32);
1414 //if(imm==1) ...
1415 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
1416 output_w32(0xe1a00020|rd_rn_rm(rt,0,rs)|(imm<<7));
1417 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs2],32-imm);
1418 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7));
1419}
1420
b9b61529 1421void emit_signextend16(int rs,int rt)
1422{
332a4533 1423 #ifndef HAVE_ARMV6
b9b61529 1424 emit_shlimm(rs,16,rt);
1425 emit_sarimm(rt,16,rt);
1426 #else
1427 assem_debug("sxth %s,%s\n",regname[rt],regname[rs]);
1428 output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs));
1429 #endif
1430}
1431
c6c3b1b3 1432void emit_signextend8(int rs,int rt)
1433{
332a4533 1434 #ifndef HAVE_ARMV6
c6c3b1b3 1435 emit_shlimm(rs,24,rt);
1436 emit_sarimm(rt,24,rt);
1437 #else
1438 assem_debug("sxtb %s,%s\n",regname[rt],regname[rs]);
1439 output_w32(0xe6af0070|rd_rn_rm(rt,0,rs));
1440 #endif
1441}
1442
57871462 1443void emit_shl(u_int rs,u_int shift,u_int rt)
1444{
1445 assert(rs<16);
1446 assert(rt<16);
1447 assert(shift<16);
1448 //if(imm==1) ...
1449 assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
1450 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8));
1451}
1452void emit_shr(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("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
1458 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8));
1459}
1460void emit_sar(u_int rs,u_int shift,u_int rt)
1461{
1462 assert(rs<16);
1463 assert(rt<16);
1464 assert(shift<16);
1465 assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
1466 output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8));
1467}
1468void emit_shlcl(int r)
1469{
1470 assem_debug("shl %%%s,%%cl\n",regname[r]);
1471 assert(0);
1472}
1473void emit_shrcl(int r)
1474{
1475 assem_debug("shr %%%s,%%cl\n",regname[r]);
1476 assert(0);
1477}
1478void emit_sarcl(int r)
1479{
1480 assem_debug("sar %%%s,%%cl\n",regname[r]);
1481 assert(0);
1482}
1483
1484void emit_shldcl(int r1,int r2)
1485{
1486 assem_debug("shld %%%s,%%%s,%%cl\n",regname[r1],regname[r2]);
1487 assert(0);
1488}
1489void emit_shrdcl(int r1,int r2)
1490{
1491 assem_debug("shrd %%%s,%%%s,%%cl\n",regname[r1],regname[r2]);
1492 assert(0);
1493}
1494void emit_orrshl(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,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
1500 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8));
1501}
1502void emit_orrshr(u_int rs,u_int shift,u_int rt)
1503{
1504 assert(rs<16);
1505 assert(rt<16);
1506 assert(shift<16);
1507 assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
1508 output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8));
1509}
1510
1511void emit_cmpimm(int rs,int imm)
1512{
1513 u_int armval;
1514 if(genimm(imm,&armval)) {
5a05d80c 1515 assem_debug("cmp %s,#%d\n",regname[rs],imm);
57871462 1516 output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval);
1517 }else if(genimm(-imm,&armval)) {
5a05d80c 1518 assem_debug("cmn %s,#%d\n",regname[rs],imm);
57871462 1519 output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval);
1520 }else if(imm>0) {
1521 assert(imm<65536);
57871462 1522 emit_movimm(imm,HOST_TEMPREG);
57871462 1523 assem_debug("cmp %s,r14\n",regname[rs]);
1524 output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG));
1525 }else{
1526 assert(imm>-65536);
57871462 1527 emit_movimm(-imm,HOST_TEMPREG);
57871462 1528 assem_debug("cmn %s,r14\n",regname[rs]);
1529 output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG));
1530 }
1531}
1532
1533void emit_cmovne(u_int *addr,int rt)
1534{
1535 assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]);
1536 assert(0);
1537}
1538void emit_cmovl(u_int *addr,int rt)
1539{
1540 assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]);
1541 assert(0);
1542}
1543void emit_cmovs(u_int *addr,int rt)
1544{
1545 assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]);
1546 assert(0);
1547}
1548void emit_cmovne_imm(int imm,int rt)
1549{
1550 assem_debug("movne %s,#%d\n",regname[rt],imm);
1551 u_int armval;
cfbd3c6e 1552 genimm_checked(imm,&armval);
57871462 1553 output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval);
1554}
1555void emit_cmovl_imm(int imm,int rt)
1556{
1557 assem_debug("movlt %s,#%d\n",regname[rt],imm);
1558 u_int armval;
cfbd3c6e 1559 genimm_checked(imm,&armval);
57871462 1560 output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval);
1561}
1562void emit_cmovb_imm(int imm,int rt)
1563{
1564 assem_debug("movcc %s,#%d\n",regname[rt],imm);
1565 u_int armval;
cfbd3c6e 1566 genimm_checked(imm,&armval);
57871462 1567 output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval);
1568}
1569void emit_cmovs_imm(int imm,int rt)
1570{
1571 assem_debug("movmi %s,#%d\n",regname[rt],imm);
1572 u_int armval;
cfbd3c6e 1573 genimm_checked(imm,&armval);
57871462 1574 output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval);
1575}
1576void emit_cmove_reg(int rs,int rt)
1577{
1578 assem_debug("moveq %s,%s\n",regname[rt],regname[rs]);
1579 output_w32(0x01a00000|rd_rn_rm(rt,0,rs));
1580}
1581void emit_cmovne_reg(int rs,int rt)
1582{
1583 assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
1584 output_w32(0x11a00000|rd_rn_rm(rt,0,rs));
1585}
1586void emit_cmovl_reg(int rs,int rt)
1587{
1588 assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
1589 output_w32(0xb1a00000|rd_rn_rm(rt,0,rs));
1590}
1591void emit_cmovs_reg(int rs,int rt)
1592{
1593 assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
1594 output_w32(0x41a00000|rd_rn_rm(rt,0,rs));
1595}
1596
1597void emit_slti32(int rs,int imm,int rt)
1598{
1599 if(rs!=rt) emit_zeroreg(rt);
1600 emit_cmpimm(rs,imm);
1601 if(rs==rt) emit_movimm(0,rt);
1602 emit_cmovl_imm(1,rt);
1603}
1604void emit_sltiu32(int rs,int imm,int rt)
1605{
1606 if(rs!=rt) emit_zeroreg(rt);
1607 emit_cmpimm(rs,imm);
1608 if(rs==rt) emit_movimm(0,rt);
1609 emit_cmovb_imm(1,rt);
1610}
1611void emit_slti64_32(int rsh,int rsl,int imm,int rt)
1612{
1613 assert(rsh!=rt);
1614 emit_slti32(rsl,imm,rt);
1615 if(imm>=0)
1616 {
1617 emit_test(rsh,rsh);
1618 emit_cmovne_imm(0,rt);
1619 emit_cmovs_imm(1,rt);
1620 }
1621 else
1622 {
1623 emit_cmpimm(rsh,-1);
1624 emit_cmovne_imm(0,rt);
1625 emit_cmovl_imm(1,rt);
1626 }
1627}
1628void emit_sltiu64_32(int rsh,int rsl,int imm,int rt)
1629{
1630 assert(rsh!=rt);
1631 emit_sltiu32(rsl,imm,rt);
1632 if(imm>=0)
1633 {
1634 emit_test(rsh,rsh);
1635 emit_cmovne_imm(0,rt);
1636 }
1637 else
1638 {
1639 emit_cmpimm(rsh,-1);
1640 emit_cmovne_imm(1,rt);
1641 }
1642}
1643
1644void emit_cmp(int rs,int rt)
1645{
1646 assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
1647 output_w32(0xe1500000|rd_rn_rm(0,rs,rt));
1648}
1649void emit_set_gz32(int rs, int rt)
1650{
1651 //assem_debug("set_gz32\n");
1652 emit_cmpimm(rs,1);
1653 emit_movimm(1,rt);
1654 emit_cmovl_imm(0,rt);
1655}
1656void emit_set_nz32(int rs, int rt)
1657{
1658 //assem_debug("set_nz32\n");
1659 if(rs!=rt) emit_movs(rs,rt);
1660 else emit_test(rs,rs);
1661 emit_cmovne_imm(1,rt);
1662}
1663void emit_set_gz64_32(int rsh, int rsl, int rt)
1664{
1665 //assem_debug("set_gz64\n");
1666 emit_set_gz32(rsl,rt);
1667 emit_test(rsh,rsh);
1668 emit_cmovne_imm(1,rt);
1669 emit_cmovs_imm(0,rt);
1670}
1671void emit_set_nz64_32(int rsh, int rsl, int rt)
1672{
1673 //assem_debug("set_nz64\n");
1674 emit_or_and_set_flags(rsh,rsl,rt);
1675 emit_cmovne_imm(1,rt);
1676}
1677void emit_set_if_less32(int rs1, int rs2, int rt)
1678{
1679 //assem_debug("set if less (%%%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_cmovl_imm(1,rt);
1684}
1685void emit_set_if_carry32(int rs1, int rs2, int rt)
1686{
1687 //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
1688 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
1689 emit_cmp(rs1,rs2);
1690 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
1691 emit_cmovb_imm(1,rt);
1692}
1693void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt)
1694{
1695 //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]);
1696 assert(u1!=rt);
1697 assert(u2!=rt);
1698 emit_cmp(l1,l2);
1699 emit_movimm(0,rt);
1700 emit_sbcs(u1,u2,HOST_TEMPREG);
1701 emit_cmovl_imm(1,rt);
1702}
1703void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt)
1704{
1705 //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]);
1706 assert(u1!=rt);
1707 assert(u2!=rt);
1708 emit_cmp(l1,l2);
1709 emit_movimm(0,rt);
1710 emit_sbcs(u1,u2,HOST_TEMPREG);
1711 emit_cmovb_imm(1,rt);
1712}
1713
1714void emit_call(int a)
1715{
1716 assem_debug("bl %x (%x+%x)\n",a,(int)out,a-(int)out-8);
1717 u_int offset=genjmp(a);
1718 output_w32(0xeb000000|offset);
1719}
1720void emit_jmp(int a)
1721{
1722 assem_debug("b %x (%x+%x)\n",a,(int)out,a-(int)out-8);
1723 u_int offset=genjmp(a);
1724 output_w32(0xea000000|offset);
1725}
1726void emit_jne(int a)
1727{
1728 assem_debug("bne %x\n",a);
1729 u_int offset=genjmp(a);
1730 output_w32(0x1a000000|offset);
1731}
1732void emit_jeq(int a)
1733{
1734 assem_debug("beq %x\n",a);
1735 u_int offset=genjmp(a);
1736 output_w32(0x0a000000|offset);
1737}
1738void emit_js(int a)
1739{
1740 assem_debug("bmi %x\n",a);
1741 u_int offset=genjmp(a);
1742 output_w32(0x4a000000|offset);
1743}
1744void emit_jns(int a)
1745{
1746 assem_debug("bpl %x\n",a);
1747 u_int offset=genjmp(a);
1748 output_w32(0x5a000000|offset);
1749}
1750void emit_jl(int a)
1751{
1752 assem_debug("blt %x\n",a);
1753 u_int offset=genjmp(a);
1754 output_w32(0xba000000|offset);
1755}
1756void emit_jge(int a)
1757{
1758 assem_debug("bge %x\n",a);
1759 u_int offset=genjmp(a);
1760 output_w32(0xaa000000|offset);
1761}
1762void emit_jno(int a)
1763{
1764 assem_debug("bvc %x\n",a);
1765 u_int offset=genjmp(a);
1766 output_w32(0x7a000000|offset);
1767}
1768void emit_jc(int a)
1769{
1770 assem_debug("bcs %x\n",a);
1771 u_int offset=genjmp(a);
1772 output_w32(0x2a000000|offset);
1773}
1774void emit_jcc(int a)
1775{
1776 assem_debug("bcc %x\n",a);
1777 u_int offset=genjmp(a);
1778 output_w32(0x3a000000|offset);
1779}
1780
1781void emit_pushimm(int imm)
1782{
1783 assem_debug("push $%x\n",imm);
1784 assert(0);
1785}
1786void emit_pusha()
1787{
1788 assem_debug("pusha\n");
1789 assert(0);
1790}
1791void emit_popa()
1792{
1793 assem_debug("popa\n");
1794 assert(0);
1795}
1796void emit_pushreg(u_int r)
1797{
1798 assem_debug("push %%%s\n",regname[r]);
1799 assert(0);
1800}
1801void emit_popreg(u_int r)
1802{
1803 assem_debug("pop %%%s\n",regname[r]);
1804 assert(0);
1805}
1806void emit_callreg(u_int r)
1807{
c6c3b1b3 1808 assert(r<15);
1809 assem_debug("blx %s\n",regname[r]);
1810 output_w32(0xe12fff30|r);
57871462 1811}
1812void emit_jmpreg(u_int r)
1813{
1814 assem_debug("mov pc,%s\n",regname[r]);
1815 output_w32(0xe1a00000|rd_rn_rm(15,0,r));
1816}
1817
1818void emit_readword_indexed(int offset, int rs, int rt)
1819{
1820 assert(offset>-4096&&offset<4096);
1821 assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
1822 if(offset>=0) {
1823 output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset);
1824 }else{
1825 output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset));
1826 }
1827}
1828void emit_readword_dualindexedx4(int rs1, int rs2, int rt)
1829{
1830 assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
1831 output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100);
1832}
c6c3b1b3 1833void emit_ldrcc_dualindexed(int rs1, int rs2, int rt)
1834{
1835 assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1836 output_w32(0x37900000|rd_rn_rm(rt,rs1,rs2));
1837}
1838void emit_ldrccb_dualindexed(int rs1, int rs2, int rt)
1839{
1840 assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1841 output_w32(0x37d00000|rd_rn_rm(rt,rs1,rs2));
1842}
1843void emit_ldrccsb_dualindexed(int rs1, int rs2, int rt)
1844{
1845 assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1846 output_w32(0x319000d0|rd_rn_rm(rt,rs1,rs2));
1847}
1848void emit_ldrcch_dualindexed(int rs1, int rs2, int rt)
1849{
1850 assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1851 output_w32(0x319000b0|rd_rn_rm(rt,rs1,rs2));
1852}
1853void emit_ldrccsh_dualindexed(int rs1, int rs2, int rt)
1854{
1855 assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1856 output_w32(0x319000f0|rd_rn_rm(rt,rs1,rs2));
1857}
57871462 1858void emit_readword_indexed_tlb(int addr, int rs, int map, int rt)
1859{
1860 if(map<0) emit_readword_indexed(addr, rs, rt);
1861 else {
1862 assert(addr==0);
1863 emit_readword_dualindexedx4(rs, map, rt);
1864 }
1865}
1866void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl)
1867{
1868 if(map<0) {
1869 if(rh>=0) emit_readword_indexed(addr, rs, rh);
1870 emit_readword_indexed(addr+4, rs, rl);
1871 }else{
1872 assert(rh!=rs);
1873 if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh);
1874 emit_addimm(map,1,map);
1875 emit_readword_indexed_tlb(addr, rs, map, rl);
1876 }
1877}
1878void emit_movsbl_indexed(int offset, int rs, int rt)
1879{
1880 assert(offset>-256&&offset<256);
1881 assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
1882 if(offset>=0) {
1883 output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1884 }else{
1885 output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1886 }
1887}
1888void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt)
1889{
1890 if(map<0) emit_movsbl_indexed(addr, rs, rt);
1891 else {
1892 if(addr==0) {
1893 emit_shlimm(map,2,map);
1894 assem_debug("ldrsb %s,%s+%s\n",regname[rt],regname[rs],regname[map]);
1895 output_w32(0xe19000d0|rd_rn_rm(rt,rs,map));
1896 }else{
1897 assert(addr>-256&&addr<256);
1898 assem_debug("add %s,%s,%s,lsl #2\n",regname[rt],regname[rs],regname[map]);
1899 output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7));
1900 emit_movsbl_indexed(addr, rt, rt);
1901 }
1902 }
1903}
1904void emit_movswl_indexed(int offset, int rs, int rt)
1905{
1906 assert(offset>-256&&offset<256);
1907 assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
1908 if(offset>=0) {
1909 output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1910 }else{
1911 output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1912 }
1913}
1914void emit_movzbl_indexed(int offset, int rs, int rt)
1915{
1916 assert(offset>-4096&&offset<4096);
1917 assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
1918 if(offset>=0) {
1919 output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset);
1920 }else{
1921 output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset));
1922 }
1923}
1924void emit_movzbl_dualindexedx4(int rs1, int rs2, int rt)
1925{
1926 assem_debug("ldrb %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
1927 output_w32(0xe7d00000|rd_rn_rm(rt,rs1,rs2)|0x100);
1928}
1929void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt)
1930{
1931 if(map<0) emit_movzbl_indexed(addr, rs, rt);
1932 else {
1933 if(addr==0) {
1934 emit_movzbl_dualindexedx4(rs, map, rt);
1935 }else{
1936 emit_addimm(rs,addr,rt);
1937 emit_movzbl_dualindexedx4(rt, map, rt);
1938 }
1939 }
1940}
1941void emit_movzwl_indexed(int offset, int rs, int rt)
1942{
1943 assert(offset>-256&&offset<256);
1944 assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
1945 if(offset>=0) {
1946 output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1947 }else{
1948 output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1949 }
1950}
054175e9 1951static void emit_ldrd(int offset, int rs, int rt)
1952{
1953 assert(offset>-256&&offset<256);
1954 assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset);
1955 if(offset>=0) {
1956 output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
1957 }else{
1958 output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
1959 }
1960}
57871462 1961void emit_readword(int addr, int rt)
1962{
1963 u_int offset = addr-(u_int)&dynarec_local;
1964 assert(offset<4096);
1965 assem_debug("ldr %s,fp+%d\n",regname[rt],offset);
1966 output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset);
1967}
1968void emit_movsbl(int addr, int rt)
1969{
1970 u_int offset = addr-(u_int)&dynarec_local;
1971 assert(offset<256);
1972 assem_debug("ldrsb %s,fp+%d\n",regname[rt],offset);
1973 output_w32(0xe1d000d0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
1974}
1975void emit_movswl(int addr, int rt)
1976{
1977 u_int offset = addr-(u_int)&dynarec_local;
1978 assert(offset<256);
1979 assem_debug("ldrsh %s,fp+%d\n",regname[rt],offset);
1980 output_w32(0xe1d000f0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
1981}
1982void emit_movzbl(int addr, int rt)
1983{
1984 u_int offset = addr-(u_int)&dynarec_local;
1985 assert(offset<4096);
1986 assem_debug("ldrb %s,fp+%d\n",regname[rt],offset);
1987 output_w32(0xe5d00000|rd_rn_rm(rt,FP,0)|offset);
1988}
1989void emit_movzwl(int addr, int rt)
1990{
1991 u_int offset = addr-(u_int)&dynarec_local;
1992 assert(offset<256);
1993 assem_debug("ldrh %s,fp+%d\n",regname[rt],offset);
1994 output_w32(0xe1d000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
1995}
1996void emit_movzwl_reg(int rs, int rt)
1997{
1998 assem_debug("movzwl %%%s,%%%s\n",regname[rs]+1,regname[rt]);
1999 assert(0);
2000}
2001
2002void emit_xchg(int rs, int rt)
2003{
2004 assem_debug("xchg %%%s,%%%s\n",regname[rs],regname[rt]);
2005 assert(0);
2006}
2007void emit_writeword_indexed(int rt, int offset, int rs)
2008{
2009 assert(offset>-4096&&offset<4096);
2010 assem_debug("str %s,%s+%d\n",regname[rt],regname[rs],offset);
2011 if(offset>=0) {
2012 output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset);
2013 }else{
2014 output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset));
2015 }
2016}
2017void emit_writeword_dualindexedx4(int rt, int rs1, int rs2)
2018{
2019 assem_debug("str %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
2020 output_w32(0xe7800000|rd_rn_rm(rt,rs1,rs2)|0x100);
2021}
2022void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map, int temp)
2023{
2024 if(map<0) emit_writeword_indexed(rt, addr, rs);
2025 else {
2026 assert(addr==0);
2027 emit_writeword_dualindexedx4(rt, rs, map);
2028 }
2029}
2030void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map, int temp)
2031{
2032 if(map<0) {
2033 if(rh>=0) emit_writeword_indexed(rh, addr, rs);
2034 emit_writeword_indexed(rl, addr+4, rs);
2035 }else{
2036 assert(rh>=0);
2037 if(temp!=rs) emit_addimm(map,1,temp);
2038 emit_writeword_indexed_tlb(rh, addr, rs, map, temp);
2039 if(temp!=rs) emit_writeword_indexed_tlb(rl, addr, rs, temp, temp);
2040 else {
2041 emit_addimm(rs,4,rs);
2042 emit_writeword_indexed_tlb(rl, addr, rs, map, temp);
2043 }
2044 }
2045}
2046void emit_writehword_indexed(int rt, int offset, int rs)
2047{
2048 assert(offset>-256&&offset<256);
2049 assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset);
2050 if(offset>=0) {
2051 output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
2052 }else{
2053 output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
2054 }
2055}
2056void emit_writebyte_indexed(int rt, int offset, int rs)
2057{
2058 assert(offset>-4096&&offset<4096);
2059 assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset);
2060 if(offset>=0) {
2061 output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset);
2062 }else{
2063 output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset));
2064 }
2065}
2066void emit_writebyte_dualindexedx4(int rt, int rs1, int rs2)
2067{
2068 assem_debug("strb %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
2069 output_w32(0xe7c00000|rd_rn_rm(rt,rs1,rs2)|0x100);
2070}
2071void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map, int temp)
2072{
2073 if(map<0) emit_writebyte_indexed(rt, addr, rs);
2074 else {
2075 if(addr==0) {
2076 emit_writebyte_dualindexedx4(rt, rs, map);
2077 }else{
2078 emit_addimm(rs,addr,temp);
2079 emit_writebyte_dualindexedx4(rt, temp, map);
2080 }
2081 }
2082}
b96d3df7 2083void emit_strcc_dualindexed(int rs1, int rs2, int rt)
2084{
2085 assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2086 output_w32(0x37800000|rd_rn_rm(rt,rs1,rs2));
2087}
2088void emit_strccb_dualindexed(int rs1, int rs2, int rt)
2089{
2090 assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2091 output_w32(0x37c00000|rd_rn_rm(rt,rs1,rs2));
2092}
2093void emit_strcch_dualindexed(int rs1, int rs2, int rt)
2094{
2095 assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2096 output_w32(0x318000b0|rd_rn_rm(rt,rs1,rs2));
2097}
57871462 2098void emit_writeword(int rt, int addr)
2099{
2100 u_int offset = addr-(u_int)&dynarec_local;
2101 assert(offset<4096);
2102 assem_debug("str %s,fp+%d\n",regname[rt],offset);
2103 output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset);
2104}
2105void emit_writehword(int rt, int addr)
2106{
2107 u_int offset = addr-(u_int)&dynarec_local;
2108 assert(offset<256);
2109 assem_debug("strh %s,fp+%d\n",regname[rt],offset);
2110 output_w32(0xe1c000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf));
2111}
2112void emit_writebyte(int rt, int addr)
2113{
2114 u_int offset = addr-(u_int)&dynarec_local;
2115 assert(offset<4096);
74426039 2116 assem_debug("strb %s,fp+%d\n",regname[rt],offset);
57871462 2117 output_w32(0xe5c00000|rd_rn_rm(rt,FP,0)|offset);
2118}
2119void emit_writeword_imm(int imm, int addr)
2120{
2121 assem_debug("movl $%x,%x\n",imm,addr);
2122 assert(0);
2123}
2124void emit_writebyte_imm(int imm, int addr)
2125{
2126 assem_debug("movb $%x,%x\n",imm,addr);
2127 assert(0);
2128}
2129
2130void emit_mul(int rs)
2131{
2132 assem_debug("mul %%%s\n",regname[rs]);
2133 assert(0);
2134}
2135void emit_imul(int rs)
2136{
2137 assem_debug("imul %%%s\n",regname[rs]);
2138 assert(0);
2139}
2140void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
2141{
2142 assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
2143 assert(rs1<16);
2144 assert(rs2<16);
2145 assert(hi<16);
2146 assert(lo<16);
2147 output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
2148}
2149void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
2150{
2151 assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
2152 assert(rs1<16);
2153 assert(rs2<16);
2154 assert(hi<16);
2155 assert(lo<16);
2156 output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1);
2157}
2158
2159void emit_div(int rs)
2160{
2161 assem_debug("div %%%s\n",regname[rs]);
2162 assert(0);
2163}
2164void emit_idiv(int rs)
2165{
2166 assem_debug("idiv %%%s\n",regname[rs]);
2167 assert(0);
2168}
2169void emit_cdq()
2170{
2171 assem_debug("cdq\n");
2172 assert(0);
2173}
2174
2175void emit_clz(int rs,int rt)
2176{
2177 assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
2178 output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs));
2179}
2180
2181void emit_subcs(int rs1,int rs2,int rt)
2182{
2183 assem_debug("subcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2184 output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2));
2185}
2186
2187void emit_shrcc_imm(int rs,u_int imm,int rt)
2188{
2189 assert(imm>0);
2190 assert(imm<32);
2191 assem_debug("lsrcc %s,%s,#%d\n",regname[rt],regname[rs],imm);
2192 output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
2193}
2194
b1be1eee 2195void emit_shrne_imm(int rs,u_int imm,int rt)
2196{
2197 assert(imm>0);
2198 assert(imm<32);
2199 assem_debug("lsrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2200 output_w32(0x11a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7));
2201}
2202
57871462 2203void emit_negmi(int rs, int rt)
2204{
2205 assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]);
2206 output_w32(0x42600000|rd_rn_rm(rt,rs,0));
2207}
2208
2209void emit_negsmi(int rs, int rt)
2210{
2211 assem_debug("rsbsmi %s,%s,#0\n",regname[rt],regname[rs]);
2212 output_w32(0x42700000|rd_rn_rm(rt,rs,0));
2213}
2214
2215void emit_orreq(u_int rs1,u_int rs2,u_int rt)
2216{
2217 assem_debug("orreq %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2218 output_w32(0x01800000|rd_rn_rm(rt,rs1,rs2));
2219}
2220
2221void emit_orrne(u_int rs1,u_int rs2,u_int rt)
2222{
2223 assem_debug("orrne %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
2224 output_w32(0x11800000|rd_rn_rm(rt,rs1,rs2));
2225}
2226
2227void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
2228{
2229 assem_debug("bic %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2230 output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
2231}
2232
2233void emit_biceq_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
2234{
2235 assem_debug("biceq %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2236 output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
2237}
2238
2239void emit_bicne_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
2240{
2241 assem_debug("bicne %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2242 output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8));
2243}
2244
2245void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
2246{
2247 assem_debug("bic %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2248 output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
2249}
2250
2251void emit_biceq_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
2252{
2253 assem_debug("biceq %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2254 output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
2255}
2256
2257void emit_bicne_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
2258{
2259 assem_debug("bicne %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]);
2260 output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8));
2261}
2262
2263void emit_teq(int rs, int rt)
2264{
2265 assem_debug("teq %s,%s\n",regname[rs],regname[rt]);
2266 output_w32(0xe1300000|rd_rn_rm(0,rs,rt));
2267}
2268
2269void emit_rsbimm(int rs, int imm, int rt)
2270{
2271 u_int armval;
cfbd3c6e 2272 genimm_checked(imm,&armval);
57871462 2273 assem_debug("rsb %s,%s,#%d\n",regname[rt],regname[rs],imm);
2274 output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval);
2275}
2276
2277// Load 2 immediates optimizing for small code size
2278void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
2279{
2280 emit_movimm(imm1,rt1);
2281 u_int armval;
2282 if(genimm(imm2-imm1,&armval)) {
2283 assem_debug("add %s,%s,#%d\n",regname[rt2],regname[rt1],imm2-imm1);
2284 output_w32(0xe2800000|rd_rn_rm(rt2,rt1,0)|armval);
2285 }else if(genimm(imm1-imm2,&armval)) {
2286 assem_debug("sub %s,%s,#%d\n",regname[rt2],regname[rt1],imm1-imm2);
2287 output_w32(0xe2400000|rd_rn_rm(rt2,rt1,0)|armval);
2288 }
2289 else emit_movimm(imm2,rt2);
2290}
2291
2292// Conditionally select one of two immediates, optimizing for small code size
2293// This will only be called if HAVE_CMOV_IMM is defined
2294void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
2295{
2296 u_int armval;
2297 if(genimm(imm2-imm1,&armval)) {
2298 emit_movimm(imm1,rt);
2299 assem_debug("addne %s,%s,#%d\n",regname[rt],regname[rt],imm2-imm1);
2300 output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval);
2301 }else if(genimm(imm1-imm2,&armval)) {
2302 emit_movimm(imm1,rt);
2303 assem_debug("subne %s,%s,#%d\n",regname[rt],regname[rt],imm1-imm2);
2304 output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval);
2305 }
2306 else {
665f33e1 2307 #ifndef HAVE_ARMV7
57871462 2308 emit_movimm(imm1,rt);
2309 add_literal((int)out,imm2);
2310 assem_debug("ldrne %s,pc+? [=%x]\n",regname[rt],imm2);
2311 output_w32(0x15900000|rd_rn_rm(rt,15,0));
2312 #else
2313 emit_movw(imm1&0x0000FFFF,rt);
2314 if((imm1&0xFFFF)!=(imm2&0xFFFF)) {
2315 assem_debug("movwne %s,#%d (0x%x)\n",regname[rt],imm2&0xFFFF,imm2&0xFFFF);
2316 output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000));
2317 }
2318 emit_movt(imm1&0xFFFF0000,rt);
2319 if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) {
2320 assem_debug("movtne %s,#%d (0x%x)\n",regname[rt],imm2&0xffff0000,imm2&0xffff0000);
2321 output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000));
2322 }
2323 #endif
2324 }
2325}
2326
2327// special case for checking invalid_code
2328void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm)
2329{
2330 assert(0);
2331}
2332
2333// special case for checking invalid_code
2334void emit_cmpmem_indexedsr12_reg(int base,int r,int imm)
2335{
2336 assert(imm<128&&imm>=0);
2337 assert(r>=0&&r<16);
2338 assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
2339 output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620);
2340 emit_cmpimm(HOST_TEMPREG,imm);
2341}
2342
2343// special case for tlb mapping
2344void emit_addsr12(int rs1,int rs2,int rt)
2345{
2346 assem_debug("add %s,%s,%s lsr #12\n",regname[rt],regname[rs1],regname[rs2]);
2347 output_w32(0xe0800620|rd_rn_rm(rt,rs1,rs2));
2348}
2349
0bbd1454 2350void emit_callne(int a)
2351{
2352 assem_debug("blne %x\n",a);
2353 u_int offset=genjmp(a);
2354 output_w32(0x1b000000|offset);
2355}
2356
57871462 2357// Used to preload hash table entries
2358void emit_prefetch(void *addr)
2359{
2360 assem_debug("prefetch %x\n",(int)addr);
2361 output_byte(0x0F);
2362 output_byte(0x18);
2363 output_modrm(0,5,1);
2364 output_w32((int)addr);
2365}
2366void emit_prefetchreg(int r)
2367{
2368 assem_debug("pld %s\n",regname[r]);
2369 output_w32(0xf5d0f000|rd_rn_rm(0,r,0));
2370}
2371
2372// Special case for mini_ht
2373void emit_ldreq_indexed(int rs, u_int offset, int rt)
2374{
2375 assert(offset<4096);
2376 assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset);
2377 output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset);
2378}
2379
2380void emit_flds(int r,int sr)
2381{
2382 assem_debug("flds s%d,[%s]\n",sr,regname[r]);
2383 output_w32(0xed900a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16));
2384}
2385
2386void emit_vldr(int r,int vr)
2387{
2388 assem_debug("vldr d%d,[%s]\n",vr,regname[r]);
2389 output_w32(0xed900b00|(vr<<12)|(r<<16));
2390}
2391
2392void emit_fsts(int sr,int r)
2393{
2394 assem_debug("fsts s%d,[%s]\n",sr,regname[r]);
2395 output_w32(0xed800a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16));
2396}
2397
2398void emit_vstr(int vr,int r)
2399{
2400 assem_debug("vstr d%d,[%s]\n",vr,regname[r]);
2401 output_w32(0xed800b00|(vr<<12)|(r<<16));
2402}
2403
2404void emit_ftosizs(int s,int d)
2405{
2406 assem_debug("ftosizs s%d,s%d\n",d,s);
2407 output_w32(0xeebd0ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2408}
2409
2410void emit_ftosizd(int s,int d)
2411{
2412 assem_debug("ftosizd s%d,d%d\n",d,s);
2413 output_w32(0xeebd0bc0|((d&14)<<11)|((d&1)<<22)|(s&7));
2414}
2415
2416void emit_fsitos(int s,int d)
2417{
2418 assem_debug("fsitos s%d,s%d\n",d,s);
2419 output_w32(0xeeb80ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2420}
2421
2422void emit_fsitod(int s,int d)
2423{
2424 assem_debug("fsitod d%d,s%d\n",d,s);
2425 output_w32(0xeeb80bc0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5));
2426}
2427
2428void emit_fcvtds(int s,int d)
2429{
2430 assem_debug("fcvtds d%d,s%d\n",d,s);
2431 output_w32(0xeeb70ac0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5));
2432}
2433
2434void emit_fcvtsd(int s,int d)
2435{
2436 assem_debug("fcvtsd s%d,d%d\n",d,s);
2437 output_w32(0xeeb70bc0|((d&14)<<11)|((d&1)<<22)|(s&7));
2438}
2439
2440void emit_fsqrts(int s,int d)
2441{
2442 assem_debug("fsqrts d%d,s%d\n",d,s);
2443 output_w32(0xeeb10ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2444}
2445
2446void emit_fsqrtd(int s,int d)
2447{
2448 assem_debug("fsqrtd s%d,d%d\n",d,s);
2449 output_w32(0xeeb10bc0|((d&7)<<12)|(s&7));
2450}
2451
2452void emit_fabss(int s,int d)
2453{
2454 assem_debug("fabss d%d,s%d\n",d,s);
2455 output_w32(0xeeb00ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2456}
2457
2458void emit_fabsd(int s,int d)
2459{
2460 assem_debug("fabsd s%d,d%d\n",d,s);
2461 output_w32(0xeeb00bc0|((d&7)<<12)|(s&7));
2462}
2463
2464void emit_fnegs(int s,int d)
2465{
2466 assem_debug("fnegs d%d,s%d\n",d,s);
2467 output_w32(0xeeb10a40|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5));
2468}
2469
2470void emit_fnegd(int s,int d)
2471{
2472 assem_debug("fnegd s%d,d%d\n",d,s);
2473 output_w32(0xeeb10b40|((d&7)<<12)|(s&7));
2474}
2475
2476void emit_fadds(int s1,int s2,int d)
2477{
2478 assem_debug("fadds s%d,s%d,s%d\n",d,s1,s2);
2479 output_w32(0xee300a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2480}
2481
2482void emit_faddd(int s1,int s2,int d)
2483{
2484 assem_debug("faddd d%d,d%d,d%d\n",d,s1,s2);
2485 output_w32(0xee300b00|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2486}
2487
2488void emit_fsubs(int s1,int s2,int d)
2489{
2490 assem_debug("fsubs s%d,s%d,s%d\n",d,s1,s2);
2491 output_w32(0xee300a40|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2492}
2493
2494void emit_fsubd(int s1,int s2,int d)
2495{
2496 assem_debug("fsubd d%d,d%d,d%d\n",d,s1,s2);
2497 output_w32(0xee300b40|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2498}
2499
2500void emit_fmuls(int s1,int s2,int d)
2501{
2502 assem_debug("fmuls s%d,s%d,s%d\n",d,s1,s2);
2503 output_w32(0xee200a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2504}
2505
2506void emit_fmuld(int s1,int s2,int d)
2507{
2508 assem_debug("fmuld d%d,d%d,d%d\n",d,s1,s2);
2509 output_w32(0xee200b00|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2510}
2511
2512void emit_fdivs(int s1,int s2,int d)
2513{
2514 assem_debug("fdivs s%d,s%d,s%d\n",d,s1,s2);
2515 output_w32(0xee800a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5));
2516}
2517
2518void emit_fdivd(int s1,int s2,int d)
2519{
2520 assem_debug("fdivd d%d,d%d,d%d\n",d,s1,s2);
2521 output_w32(0xee800b00|((d&7)<<12)|((s1&7)<<16)|(s2&7));
2522}
2523
2524void emit_fcmps(int x,int y)
2525{
2526 assem_debug("fcmps s14, s15\n");
2527 output_w32(0xeeb47a67);
2528}
2529
2530void emit_fcmpd(int x,int y)
2531{
2532 assem_debug("fcmpd d6, d7\n");
2533 output_w32(0xeeb46b47);
2534}
2535
2536void emit_fmstat()
2537{
2538 assem_debug("fmstat\n");
2539 output_w32(0xeef1fa10);
2540}
2541
2542void emit_bicne_imm(int rs,int imm,int rt)
2543{
2544 u_int armval;
cfbd3c6e 2545 genimm_checked(imm,&armval);
57871462 2546 assem_debug("bicne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2547 output_w32(0x13c00000|rd_rn_rm(rt,rs,0)|armval);
2548}
2549
2550void emit_biccs_imm(int rs,int imm,int rt)
2551{
2552 u_int armval;
cfbd3c6e 2553 genimm_checked(imm,&armval);
57871462 2554 assem_debug("biccs %s,%s,#%d\n",regname[rt],regname[rs],imm);
2555 output_w32(0x23c00000|rd_rn_rm(rt,rs,0)|armval);
2556}
2557
2558void emit_bicvc_imm(int rs,int imm,int rt)
2559{
2560 u_int armval;
cfbd3c6e 2561 genimm_checked(imm,&armval);
57871462 2562 assem_debug("bicvc %s,%s,#%d\n",regname[rt],regname[rs],imm);
2563 output_w32(0x73c00000|rd_rn_rm(rt,rs,0)|armval);
2564}
2565
2566void emit_bichi_imm(int rs,int imm,int rt)
2567{
2568 u_int armval;
cfbd3c6e 2569 genimm_checked(imm,&armval);
57871462 2570 assem_debug("bichi %s,%s,#%d\n",regname[rt],regname[rs],imm);
2571 output_w32(0x83c00000|rd_rn_rm(rt,rs,0)|armval);
2572}
2573
2574void emit_orrvs_imm(int rs,int imm,int rt)
2575{
2576 u_int armval;
cfbd3c6e 2577 genimm_checked(imm,&armval);
57871462 2578 assem_debug("orrvs %s,%s,#%d\n",regname[rt],regname[rs],imm);
2579 output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval);
2580}
2581
b9b61529 2582void emit_orrne_imm(int rs,int imm,int rt)
2583{
2584 u_int armval;
cfbd3c6e 2585 genimm_checked(imm,&armval);
b9b61529 2586 assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2587 output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval);
2588}
2589
2590void emit_andne_imm(int rs,int imm,int rt)
2591{
2592 u_int armval;
cfbd3c6e 2593 genimm_checked(imm,&armval);
b9b61529 2594 assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm);
2595 output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval);
2596}
2597
665f33e1 2598void emit_addpl_imm(int rs,int imm,int rt)
2599{
2600 u_int armval;
2601 genimm_checked(imm,&armval);
2602 assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm);
2603 output_w32(0x52800000|rd_rn_rm(rt,rs,0)|armval);
2604}
2605
57871462 2606void emit_jno_unlikely(int a)
2607{
2608 //emit_jno(a);
2609 assem_debug("addvc pc,pc,#? (%x)\n",/*a-(int)out-8,*/a);
2610 output_w32(0x72800000|rd_rn_rm(15,15,0));
2611}
2612
054175e9 2613static void save_regs_all(u_int reglist)
57871462 2614{
054175e9 2615 int i;
57871462 2616 if(!reglist) return;
2617 assem_debug("stmia fp,{");
054175e9 2618 for(i=0;i<16;i++)
2619 if(reglist&(1<<i))
2620 assem_debug("r%d,",i);
57871462 2621 assem_debug("}\n");
2622 output_w32(0xe88b0000|reglist);
2623}
054175e9 2624static void restore_regs_all(u_int reglist)
57871462 2625{
054175e9 2626 int i;
57871462 2627 if(!reglist) return;
2628 assem_debug("ldmia fp,{");
054175e9 2629 for(i=0;i<16;i++)
2630 if(reglist&(1<<i))
2631 assem_debug("r%d,",i);
57871462 2632 assem_debug("}\n");
2633 output_w32(0xe89b0000|reglist);
2634}
054175e9 2635// Save registers before function call
2636static void save_regs(u_int reglist)
2637{
4d646738 2638 reglist&=CALLER_SAVE_REGS; // only save the caller-save registers, r0-r3, r12
054175e9 2639 save_regs_all(reglist);
2640}
2641// Restore registers after function call
2642static void restore_regs(u_int reglist)
2643{
4d646738 2644 reglist&=CALLER_SAVE_REGS;
054175e9 2645 restore_regs_all(reglist);
2646}
57871462 2647
2648// Write back consts using r14 so we don't disturb the other registers
2649void wb_consts(signed char i_regmap[],uint64_t i_is32,u_int i_dirty,int i)
2650{
2651 int hr;
2652 for(hr=0;hr<HOST_REGS;hr++) {
2653 if(hr!=EXCLUDE_REG&&i_regmap[hr]>=0&&((i_dirty>>hr)&1)) {
2654 if(((regs[i].isconst>>hr)&1)&&i_regmap[hr]>0) {
2655 if(i_regmap[hr]<64 || !((i_is32>>(i_regmap[hr]&63))&1) ) {
2656 int value=constmap[i][hr];
2657 if(value==0) {
2658 emit_zeroreg(HOST_TEMPREG);
2659 }
2660 else {
2661 emit_movimm(value,HOST_TEMPREG);
2662 }
2663 emit_storereg(i_regmap[hr],HOST_TEMPREG);
24385cae 2664#ifndef FORCE32
57871462 2665 if((i_is32>>i_regmap[hr])&1) {
2666 if(value!=-1&&value!=0) emit_sarimm(HOST_TEMPREG,31,HOST_TEMPREG);
2667 emit_storereg(i_regmap[hr]|64,HOST_TEMPREG);
2668 }
24385cae 2669#endif
57871462 2670 }
2671 }
2672 }
2673 }
2674}
2675
2676/* Stubs/epilogue */
2677
2678void literal_pool(int n)
2679{
2680 if(!literalcount) return;
2681 if(n) {
2682 if((int)out-literals[0][0]<4096-n) return;
2683 }
2684 u_int *ptr;
2685 int i;
2686 for(i=0;i<literalcount;i++)
2687 {
77750690 2688 u_int l_addr=(u_int)out;
2689 int j;
2690 for(j=0;j<i;j++) {
2691 if(literals[j][1]==literals[i][1]) {
2692 //printf("dup %08x\n",literals[i][1]);
2693 l_addr=literals[j][0];
2694 break;
2695 }
2696 }
57871462 2697 ptr=(u_int *)literals[i][0];
77750690 2698 u_int offset=l_addr-(u_int)ptr-8;
57871462 2699 assert(offset<4096);
2700 assert(!(offset&3));
2701 *ptr|=offset;
77750690 2702 if(l_addr==(u_int)out) {
2703 literals[i][0]=l_addr; // remember for dupes
2704 output_w32(literals[i][1]);
2705 }
57871462 2706 }
2707 literalcount=0;
2708}
2709
2710void literal_pool_jumpover(int n)
2711{
2712 if(!literalcount) return;
2713 if(n) {
2714 if((int)out-literals[0][0]<4096-n) return;
2715 }
2716 int jaddr=(int)out;
2717 emit_jmp(0);
2718 literal_pool(0);
2719 set_jump_target(jaddr,(int)out);
2720}
2721
c67af2ac 2722emit_extjump2(u_int addr, int target, int linker)
57871462 2723{
2724 u_char *ptr=(u_char *)addr;
2725 assert((ptr[3]&0x0e)==0xa);
2726 emit_loadlp(target,0);
2727 emit_loadlp(addr,1);
24385cae 2728 assert(addr>=BASE_ADDR&&addr<(BASE_ADDR+(1<<TARGET_SIZE_2)));
57871462 2729 //assert((target>=0x80000000&&target<0x80800000)||(target>0xA4000000&&target<0xA4001000));
2730//DEBUG >
2731#ifdef DEBUG_CYCLE_COUNT
2732 emit_readword((int)&last_count,ECX);
2733 emit_add(HOST_CCREG,ECX,HOST_CCREG);
2734 emit_readword((int)&next_interupt,ECX);
2735 emit_writeword(HOST_CCREG,(int)&Count);
2736 emit_sub(HOST_CCREG,ECX,HOST_CCREG);
2737 emit_writeword(ECX,(int)&last_count);
2738#endif
2739//DEBUG <
2740 emit_jmp(linker);
2741}
2742
2743emit_extjump(int addr, int target)
2744{
2745 emit_extjump2(addr, target, (int)dyna_linker);
2746}
2747emit_extjump_ds(int addr, int target)
2748{
2749 emit_extjump2(addr, target, (int)dyna_linker_ds);
2750}
2751
13e35c04 2752// put rt_val into rt, potentially making use of rs with value rs_val
2753static void emit_movimm_from(u_int rs_val,int rs,u_int rt_val,int rt)
2754{
8575a877 2755 u_int armval;
2756 int diff;
2757 if(genimm(rt_val,&armval)) {
2758 assem_debug("mov %s,#%d\n",regname[rt],rt_val);
2759 output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
2760 return;
2761 }
2762 if(genimm(~rt_val,&armval)) {
2763 assem_debug("mvn %s,#%d\n",regname[rt],rt_val);
2764 output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
2765 return;
2766 }
2767 diff=rt_val-rs_val;
2768 if(genimm(diff,&armval)) {
2769 assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],diff);
2770 output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
2771 return;
2772 }else if(genimm(-diff,&armval)) {
2773 assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-diff);
2774 output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
2775 return;
2776 }
2777 emit_movimm(rt_val,rt);
2778}
2779
2780// return 1 if above function can do it's job cheaply
2781static int is_similar_value(u_int v1,u_int v2)
2782{
13e35c04 2783 u_int xs;
8575a877 2784 int diff;
2785 if(v1==v2) return 1;
2786 diff=v2-v1;
2787 for(xs=diff;xs!=0&&(xs&3)==0;xs>>=2)
13e35c04 2788 ;
8575a877 2789 if(xs<0x100) return 1;
2790 for(xs=-diff;xs!=0&&(xs&3)==0;xs>>=2)
2791 ;
2792 if(xs<0x100) return 1;
2793 return 0;
13e35c04 2794}
cbbab9cd 2795
b96d3df7 2796// trashes r2
2797static void pass_args(int a0, int a1)
2798{
2799 if(a0==1&&a1==0) {
2800 // must swap
2801 emit_mov(a0,2); emit_mov(a1,1); emit_mov(2,0);
2802 }
2803 else if(a0!=0&&a1==0) {
2804 emit_mov(a1,1);
2805 if (a0>=0) emit_mov(a0,0);
2806 }
2807 else {
2808 if(a0>=0&&a0!=0) emit_mov(a0,0);
2809 if(a1>=0&&a1!=1) emit_mov(a1,1);
2810 }
2811}
2812
b1be1eee 2813static void mov_loadtype_adj(int type,int rs,int rt)
2814{
2815 switch(type) {
2816 case LOADB_STUB: emit_signextend8(rs,rt); break;
2817 case LOADBU_STUB: emit_andimm(rs,0xff,rt); break;
2818 case LOADH_STUB: emit_signextend16(rs,rt); break;
2819 case LOADHU_STUB: emit_andimm(rs,0xffff,rt); break;
2820 case LOADW_STUB: if(rs!=rt) emit_mov(rs,rt); break;
2821 default: assert(0);
2822 }
2823}
2824
2825#ifdef PCSX
2826#include "pcsxmem.h"
2827#include "pcsxmem_inline.c"
2828#endif
2829
57871462 2830do_readstub(int n)
2831{
2832 assem_debug("do_readstub %x\n",start+stubs[n][3]*4);
2833 literal_pool(256);
2834 set_jump_target(stubs[n][1],(int)out);
2835 int type=stubs[n][0];
2836 int i=stubs[n][3];
2837 int rs=stubs[n][4];
2838 struct regstat *i_regs=(struct regstat *)stubs[n][5];
2839 u_int reglist=stubs[n][7];
2840 signed char *i_regmap=i_regs->regmap;
2841 int addr=get_reg(i_regmap,AGEN1+(i&1));
2842 int rth,rt;
2843 int ds;
b9b61529 2844 if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) {
57871462 2845 rth=get_reg(i_regmap,FTEMP|64);
2846 rt=get_reg(i_regmap,FTEMP);
2847 }else{
2848 rth=get_reg(i_regmap,rt1[i]|64);
2849 rt=get_reg(i_regmap,rt1[i]);
2850 }
2851 assert(rs>=0);
c6c3b1b3 2852#ifdef PCSX
2853 int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0;
2854 reglist|=(1<<rs);
2855 for(r=0;r<=12;r++) {
2856 if(((1<<r)&0x13ff)&&((1<<r)&reglist)==0) {
2857 temp=r; break;
2858 }
2859 }
db829eeb 2860 if(rt>=0&&rt1[i]!=0)
c6c3b1b3 2861 reglist&=~(1<<rt);
2862 if(temp==-1) {
2863 save_regs(reglist);
2864 regs_saved=1;
2865 temp=(rs==0)?2:0;
2866 }
2867 if((regs_saved||(reglist&2)==0)&&temp!=1&&rs!=1)
2868 temp2=1;
2869 emit_readword((int)&mem_rtab,temp);
2870 emit_shrimm(rs,12,temp2);
2871 emit_readword_dualindexedx4(temp,temp2,temp2);
2872 emit_lsls_imm(temp2,1,temp2);
2873 if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
2874 switch(type) {
2875 case LOADB_STUB: emit_ldrccsb_dualindexed(temp2,rs,rt); break;
2876 case LOADBU_STUB: emit_ldrccb_dualindexed(temp2,rs,rt); break;
2877 case LOADH_STUB: emit_ldrccsh_dualindexed(temp2,rs,rt); break;
2878 case LOADHU_STUB: emit_ldrcch_dualindexed(temp2,rs,rt); break;
2879 case LOADW_STUB: emit_ldrcc_dualindexed(temp2,rs,rt); break;
2880 }
2881 }
2882 if(regs_saved) {
2883 restore_jump=(int)out;
2884 emit_jcc(0); // jump to reg restore
2885 }
2886 else
2887 emit_jcc(stubs[n][2]); // return address
2888
2889 if(!regs_saved)
2890 save_regs(reglist);
2891 int handler=0;
2892 if(type==LOADB_STUB||type==LOADBU_STUB)
2893 handler=(int)jump_handler_read8;
2894 if(type==LOADH_STUB||type==LOADHU_STUB)
2895 handler=(int)jump_handler_read16;
2896 if(type==LOADW_STUB)
2897 handler=(int)jump_handler_read32;
2898 assert(handler!=0);
b96d3df7 2899 pass_args(rs,temp2);
c6c3b1b3 2900 int cc=get_reg(i_regmap,CCREG);
2901 if(cc<0)
2902 emit_loadreg(CCREG,2);
2573466a 2903 emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
c6c3b1b3 2904 emit_call(handler);
2905 if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
b1be1eee 2906 mov_loadtype_adj(type,0,rt);
c6c3b1b3 2907 }
2908 if(restore_jump)
2909 set_jump_target(restore_jump,(int)out);
2910 restore_regs(reglist);
2911 emit_jmp(stubs[n][2]); // return address
2912#else // !PCSX
57871462 2913 if(addr<0) addr=rt;
535d208a 2914 if(addr<0&&itype[i]!=C1LS&&itype[i]!=C2LS&&itype[i]!=LOADLR) addr=get_reg(i_regmap,-1);
57871462 2915 assert(addr>=0);
2916 int ftable=0;
2917 if(type==LOADB_STUB||type==LOADBU_STUB)
2918 ftable=(int)readmemb;
2919 if(type==LOADH_STUB||type==LOADHU_STUB)
2920 ftable=(int)readmemh;
2921 if(type==LOADW_STUB)
2922 ftable=(int)readmem;
24385cae 2923#ifndef FORCE32
57871462 2924 if(type==LOADD_STUB)
2925 ftable=(int)readmemd;
24385cae 2926#endif
2927 assert(ftable!=0);
57871462 2928 emit_writeword(rs,(int)&address);
2929 //emit_pusha();
2930 save_regs(reglist);
97a238a6 2931#ifndef PCSX
57871462 2932 ds=i_regs!=&regs[i];
2933 int real_rs=(itype[i]==LOADLR)?-1:get_reg(i_regmap,rs1[i]);
2934 u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
2935 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);
2936 wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
2937 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 2938#endif
57871462 2939 emit_shrimm(rs,16,1);
2940 int cc=get_reg(i_regmap,CCREG);
2941 if(cc<0) {
2942 emit_loadreg(CCREG,2);
2943 }
2944 emit_movimm(ftable,0);
2945 emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
f51dc36c 2946#ifndef PCSX
57871462 2947 emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
f51dc36c 2948#endif
57871462 2949 //emit_readword((int)&last_count,temp);
2950 //emit_add(cc,temp,cc);
2951 //emit_writeword(cc,(int)&Count);
2952 //emit_mov(15,14);
2953 emit_call((int)&indirect_jump_indexed);
2954 //emit_callreg(rs);
2955 //emit_readword_dualindexedx4(rs,HOST_TEMPREG,15);
f51dc36c 2956#ifndef PCSX
57871462 2957 // We really shouldn't need to update the count here,
2958 // but not doing so causes random crashes...
2959 emit_readword((int)&Count,HOST_TEMPREG);
2960 emit_readword((int)&next_interupt,2);
2961 emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG);
2962 emit_writeword(2,(int)&last_count);
2963 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
2964 if(cc<0) {
2965 emit_storereg(CCREG,HOST_TEMPREG);
2966 }
f51dc36c 2967#endif
57871462 2968 //emit_popa();
2969 restore_regs(reglist);
2970 //if((cc=get_reg(regmap,CCREG))>=0) {
2971 // emit_loadreg(CCREG,cc);
2972 //}
f18c0f46 2973 if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
2974 assert(rt>=0);
2975 if(type==LOADB_STUB)
2976 emit_movsbl((int)&readmem_dword,rt);
2977 if(type==LOADBU_STUB)
2978 emit_movzbl((int)&readmem_dword,rt);
2979 if(type==LOADH_STUB)
2980 emit_movswl((int)&readmem_dword,rt);
2981 if(type==LOADHU_STUB)
2982 emit_movzwl((int)&readmem_dword,rt);
2983 if(type==LOADW_STUB)
2984 emit_readword((int)&readmem_dword,rt);
2985 if(type==LOADD_STUB) {
2986 emit_readword((int)&readmem_dword,rt);
2987 if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
2988 }
57871462 2989 }
2990 emit_jmp(stubs[n][2]); // return address
c6c3b1b3 2991#endif // !PCSX
57871462 2992}
2993
c6c3b1b3 2994#ifdef PCSX
2995// return memhandler, or get directly accessable address and return 0
2996u_int get_direct_memhandler(void *table,u_int addr,int type,u_int *addr_host)
2997{
2998 u_int l1,l2=0;
2999 l1=((u_int *)table)[addr>>12];
3000 if((l1&(1<<31))==0) {
3001 u_int v=l1<<1;
3002 *addr_host=v+addr;
3003 return 0;
3004 }
3005 else {
3006 l1<<=1;
3007 if(type==LOADB_STUB||type==LOADBU_STUB||type==STOREB_STUB)
3008 l2=((u_int *)l1)[0x1000/4 + 0x1000/2 + (addr&0xfff)];
b96d3df7 3009 else if(type==LOADH_STUB||type==LOADHU_STUB||type==STOREH_STUB)
c6c3b1b3 3010 l2=((u_int *)l1)[0x1000/4 + (addr&0xfff)/2];
3011 else
3012 l2=((u_int *)l1)[(addr&0xfff)/4];
3013 if((l2&(1<<31))==0) {
3014 u_int v=l2<<1;
3015 *addr_host=v+(addr&0xfff);
3016 return 0;
3017 }
3018 return l2<<1;
3019 }
3020}
3021#endif
3022
57871462 3023inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
3024{
3025 int rs=get_reg(regmap,target);
3026 int rth=get_reg(regmap,target|64);
3027 int rt=get_reg(regmap,target);
535d208a 3028 if(rs<0) rs=get_reg(regmap,-1);
57871462 3029 assert(rs>=0);
c6c3b1b3 3030#ifdef PCSX
b1be1eee 3031 u_int handler,host_addr=0,is_dynamic,far_call=0;
3032 int cc=get_reg(regmap,CCREG);
3033 if(pcsx_direct_read(type,addr,CLOCK_ADJUST(adj+1),cc,target?rs:-1,rt))
3034 return;
c6c3b1b3 3035 handler=get_direct_memhandler(mem_rtab,addr,type,&host_addr);
3036 if (handler==0) {
db829eeb 3037 if(rt<0||rt1[i]==0)
c6c3b1b3 3038 return;
13e35c04 3039 if(addr!=host_addr)
3040 emit_movimm_from(addr,rs,host_addr,rs);
c6c3b1b3 3041 switch(type) {
3042 case LOADB_STUB: emit_movsbl_indexed(0,rs,rt); break;
3043 case LOADBU_STUB: emit_movzbl_indexed(0,rs,rt); break;
3044 case LOADH_STUB: emit_movswl_indexed(0,rs,rt); break;
3045 case LOADHU_STUB: emit_movzwl_indexed(0,rs,rt); break;
3046 case LOADW_STUB: emit_readword_indexed(0,rs,rt); break;
3047 default: assert(0);
3048 }
3049 return;
3050 }
b1be1eee 3051 is_dynamic=pcsxmem_is_handler_dynamic(addr);
3052 if(is_dynamic) {
3053 if(type==LOADB_STUB||type==LOADBU_STUB)
3054 handler=(int)jump_handler_read8;
3055 if(type==LOADH_STUB||type==LOADHU_STUB)
3056 handler=(int)jump_handler_read16;
3057 if(type==LOADW_STUB)
3058 handler=(int)jump_handler_read32;
3059 }
c6c3b1b3 3060
3061 // call a memhandler
db829eeb 3062 if(rt>=0&&rt1[i]!=0)
c6c3b1b3 3063 reglist&=~(1<<rt);
3064 save_regs(reglist);
3065 if(target==0)
3066 emit_movimm(addr,0);
3067 else if(rs!=0)
3068 emit_mov(rs,0);
c6c3b1b3 3069 int offset=(int)handler-(int)out-8;
3070 if(offset<-33554432||offset>=33554432) {
3071 // unreachable memhandler, a plugin func perhaps
b1be1eee 3072 emit_movimm(handler,12);
3073 far_call=1;
3074 }
3075 if(cc<0)
3076 emit_loadreg(CCREG,2);
3077 if(is_dynamic) {
3078 emit_movimm(((u_int *)mem_rtab)[addr>>12]<<1,1);
3079 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
c6c3b1b3 3080 }
b1be1eee 3081 else {
3082 emit_readword((int)&last_count,3);
3083 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
3084 emit_add(2,3,2);
3085 emit_writeword(2,(int)&Count);
3086 }
3087
3088 if(far_call)
3089 emit_callreg(12);
c6c3b1b3 3090 else
3091 emit_call(handler);
b1be1eee 3092
db829eeb 3093 if(rt>=0&&rt1[i]!=0) {
c6c3b1b3 3094 switch(type) {
3095 case LOADB_STUB: emit_signextend8(0,rt); break;
3096 case LOADBU_STUB: emit_andimm(0,0xff,rt); break;
3097 case LOADH_STUB: emit_signextend16(0,rt); break;
3098 case LOADHU_STUB: emit_andimm(0,0xffff,rt); break;
3099 case LOADW_STUB: if(rt!=0) emit_mov(0,rt); break;
3100 default: assert(0);
3101 }
3102 }
3103 restore_regs(reglist);
3104#else // if !PCSX
57871462 3105 int ftable=0;
3106 if(type==LOADB_STUB||type==LOADBU_STUB)
3107 ftable=(int)readmemb;
3108 if(type==LOADH_STUB||type==LOADHU_STUB)
3109 ftable=(int)readmemh;
3110 if(type==LOADW_STUB)
3111 ftable=(int)readmem;
24385cae 3112#ifndef FORCE32
57871462 3113 if(type==LOADD_STUB)
3114 ftable=(int)readmemd;
24385cae 3115#endif
3116 assert(ftable!=0);
fd99c415 3117 if(target==0)
3118 emit_movimm(addr,rs);
57871462 3119 emit_writeword(rs,(int)&address);
3120 //emit_pusha();
3121 save_regs(reglist);
0c1fe38b 3122#ifndef PCSX
3123 if((signed int)addr>=(signed int)0xC0000000) {
3124 // Theoretically we can have a pagefault here, if the TLB has never
3125 // been enabled and the address is outside the range 80000000..BFFFFFFF
3126 // Write out the registers so the pagefault can be handled. This is
3127 // a very rare case and likely represents a bug.
3128 int ds=regmap!=regs[i].regmap;
3129 if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
3130 if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
3131 else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty);
3132 }
3133#endif
57871462 3134 //emit_shrimm(rs,16,1);
3135 int cc=get_reg(regmap,CCREG);
3136 if(cc<0) {
3137 emit_loadreg(CCREG,2);
3138 }
3139 //emit_movimm(ftable,0);
3140 emit_movimm(((u_int *)ftable)[addr>>16],0);
3141 //emit_readword((int)&last_count,12);
2573466a 3142 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
f51dc36c 3143#ifndef PCSX
57871462 3144 if((signed int)addr>=(signed int)0xC0000000) {
3145 // Pagefault address
3146 int ds=regmap!=regs[i].regmap;
3147 emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
3148 }
f51dc36c 3149#endif
57871462 3150 //emit_add(12,2,2);
3151 //emit_writeword(2,(int)&Count);
3152 //emit_call(((u_int *)ftable)[addr>>16]);
3153 emit_call((int)&indirect_jump);
f51dc36c 3154#ifndef PCSX
57871462 3155 // We really shouldn't need to update the count here,
3156 // but not doing so causes random crashes...
3157 emit_readword((int)&Count,HOST_TEMPREG);
3158 emit_readword((int)&next_interupt,2);
2573466a 3159 emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG);
57871462 3160 emit_writeword(2,(int)&last_count);
3161 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
3162 if(cc<0) {
3163 emit_storereg(CCREG,HOST_TEMPREG);
3164 }
f51dc36c 3165#endif
57871462 3166 //emit_popa();
3167 restore_regs(reglist);
fd99c415 3168 if(rt>=0) {
3169 if(type==LOADB_STUB)
3170 emit_movsbl((int)&readmem_dword,rt);
3171 if(type==LOADBU_STUB)
3172 emit_movzbl((int)&readmem_dword,rt);
3173 if(type==LOADH_STUB)
3174 emit_movswl((int)&readmem_dword,rt);
3175 if(type==LOADHU_STUB)
3176 emit_movzwl((int)&readmem_dword,rt);
3177 if(type==LOADW_STUB)
3178 emit_readword((int)&readmem_dword,rt);
3179 if(type==LOADD_STUB) {
3180 emit_readword((int)&readmem_dword,rt);
3181 if(rth>=0) emit_readword(((int)&readmem_dword)+4,rth);
3182 }
57871462 3183 }
c6c3b1b3 3184#endif // !PCSX
57871462 3185}
3186
3187do_writestub(int n)
3188{
3189 assem_debug("do_writestub %x\n",start+stubs[n][3]*4);
3190 literal_pool(256);
3191 set_jump_target(stubs[n][1],(int)out);
3192 int type=stubs[n][0];
3193 int i=stubs[n][3];
3194 int rs=stubs[n][4];
3195 struct regstat *i_regs=(struct regstat *)stubs[n][5];
3196 u_int reglist=stubs[n][7];
3197 signed char *i_regmap=i_regs->regmap;
3198 int addr=get_reg(i_regmap,AGEN1+(i&1));
3199 int rth,rt,r;
3200 int ds;
b9b61529 3201 if(itype[i]==C1LS||itype[i]==C2LS) {
57871462 3202 rth=get_reg(i_regmap,FTEMP|64);
3203 rt=get_reg(i_regmap,r=FTEMP);
3204 }else{
3205 rth=get_reg(i_regmap,rs2[i]|64);
3206 rt=get_reg(i_regmap,r=rs2[i]);
3207 }
3208 assert(rs>=0);
3209 assert(rt>=0);
b96d3df7 3210#ifdef PCSX
3211 int rtmp,temp=-1,temp2=HOST_TEMPREG,regs_saved=0,restore_jump=0,ra;
3212 int reglist2=reglist|(1<<rs)|(1<<rt);
3213 for(rtmp=0;rtmp<=12;rtmp++) {
3214 if(((1<<rtmp)&0x13ff)&&((1<<rtmp)&reglist2)==0) {
3215 temp=rtmp; break;
3216 }
3217 }
3218 if(temp==-1) {
3219 save_regs(reglist);
3220 regs_saved=1;
3221 for(rtmp=0;rtmp<=3;rtmp++)
3222 if(rtmp!=rs&&rtmp!=rt)
3223 {temp=rtmp;break;}
3224 }
3225 if((regs_saved||(reglist2&8)==0)&&temp!=3&&rs!=3&&rt!=3)
3226 temp2=3;
3227 emit_readword((int)&mem_wtab,temp);
3228 emit_shrimm(rs,12,temp2);
3229 emit_readword_dualindexedx4(temp,temp2,temp2);
3230 emit_lsls_imm(temp2,1,temp2);
3231 switch(type) {
3232 case STOREB_STUB: emit_strccb_dualindexed(temp2,rs,rt); break;
3233 case STOREH_STUB: emit_strcch_dualindexed(temp2,rs,rt); break;
3234 case STOREW_STUB: emit_strcc_dualindexed(temp2,rs,rt); break;
3235 default: assert(0);
3236 }
3237 if(regs_saved) {
3238 restore_jump=(int)out;
3239 emit_jcc(0); // jump to reg restore
3240 }
3241 else
3242 emit_jcc(stubs[n][2]); // return address (invcode check)
3243
3244 if(!regs_saved)
3245 save_regs(reglist);
3246 int handler=0;
3247 switch(type) {
3248 case STOREB_STUB: handler=(int)jump_handler_write8; break;
3249 case STOREH_STUB: handler=(int)jump_handler_write16; break;
3250 case STOREW_STUB: handler=(int)jump_handler_write32; break;
3251 }
3252 assert(handler!=0);
3253 pass_args(rs,rt);
3254 if(temp2!=3)
3255 emit_mov(temp2,3);
3256 int cc=get_reg(i_regmap,CCREG);
3257 if(cc<0)
3258 emit_loadreg(CCREG,2);
2573466a 3259 emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
b96d3df7 3260 // returns new cycle_count
3261 emit_call(handler);
2573466a 3262 emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc);
b96d3df7 3263 if(cc<0)
3264 emit_storereg(CCREG,2);
3265 if(restore_jump)
3266 set_jump_target(restore_jump,(int)out);
3267 restore_regs(reglist);
3268 ra=stubs[n][2];
b96d3df7 3269 emit_jmp(ra);
3270#else // if !PCSX
57871462 3271 if(addr<0) addr=get_reg(i_regmap,-1);
3272 assert(addr>=0);
3273 int ftable=0;
3274 if(type==STOREB_STUB)
3275 ftable=(int)writememb;
3276 if(type==STOREH_STUB)
3277 ftable=(int)writememh;
3278 if(type==STOREW_STUB)
3279 ftable=(int)writemem;
24385cae 3280#ifndef FORCE32
57871462 3281 if(type==STORED_STUB)
3282 ftable=(int)writememd;
24385cae 3283#endif
3284 assert(ftable!=0);
57871462 3285 emit_writeword(rs,(int)&address);
3286 //emit_shrimm(rs,16,rs);
3287 //emit_movmem_indexedx4(ftable,rs,rs);
3288 if(type==STOREB_STUB)
3289 emit_writebyte(rt,(int)&byte);
3290 if(type==STOREH_STUB)
3291 emit_writehword(rt,(int)&hword);
3292 if(type==STOREW_STUB)
3293 emit_writeword(rt,(int)&word);
3294 if(type==STORED_STUB) {
3d624f89 3295#ifndef FORCE32
57871462 3296 emit_writeword(rt,(int)&dword);
3297 emit_writeword(r?rth:rt,(int)&dword+4);
3d624f89 3298#else
c43b5311 3299 SysPrintf("STORED_STUB\n");
3d624f89 3300#endif
57871462 3301 }
3302 //emit_pusha();
3303 save_regs(reglist);
97a238a6 3304#ifndef PCSX
57871462 3305 ds=i_regs!=&regs[i];
3306 int real_rs=get_reg(i_regmap,rs1[i]);
3307 u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
3308 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);
3309 wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
3310 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 3311#endif
57871462 3312 emit_shrimm(rs,16,1);
3313 int cc=get_reg(i_regmap,CCREG);
3314 if(cc<0) {
3315 emit_loadreg(CCREG,2);
3316 }
3317 emit_movimm(ftable,0);
3318 emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
f51dc36c 3319#ifndef PCSX
57871462 3320 emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
f51dc36c 3321#endif
57871462 3322 //emit_readword((int)&last_count,temp);
3323 //emit_addimm(cc,2*stubs[n][5]+2,cc);
3324 //emit_add(cc,temp,cc);
3325 //emit_writeword(cc,(int)&Count);
3326 emit_call((int)&indirect_jump_indexed);
3327 //emit_callreg(rs);
3328 emit_readword((int)&Count,HOST_TEMPREG);
3329 emit_readword((int)&next_interupt,2);
3330 emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG);
3331 emit_writeword(2,(int)&last_count);
3332 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
3333 if(cc<0) {
3334 emit_storereg(CCREG,HOST_TEMPREG);
3335 }
3336 //emit_popa();
3337 restore_regs(reglist);
3338 //if((cc=get_reg(regmap,CCREG))>=0) {
3339 // emit_loadreg(CCREG,cc);
3340 //}
3341 emit_jmp(stubs[n][2]); // return address
b96d3df7 3342#endif // !PCSX
57871462 3343}
3344
3345inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
3346{
3347 int rs=get_reg(regmap,-1);
3348 int rth=get_reg(regmap,target|64);
3349 int rt=get_reg(regmap,target);
3350 assert(rs>=0);
3351 assert(rt>=0);
cbbab9cd 3352#ifdef PCSX
b96d3df7 3353 u_int handler,host_addr=0;
b96d3df7 3354 handler=get_direct_memhandler(mem_wtab,addr,type,&host_addr);
3355 if (handler==0) {
13e35c04 3356 if(addr!=host_addr)
3357 emit_movimm_from(addr,rs,host_addr,rs);
b96d3df7 3358 switch(type) {
3359 case STOREB_STUB: emit_writebyte_indexed(rt,0,rs); break;
3360 case STOREH_STUB: emit_writehword_indexed(rt,0,rs); break;
3361 case STOREW_STUB: emit_writeword_indexed(rt,0,rs); break;
3362 default: assert(0);
3363 }
3364 return;
3365 }
3366
3367 // call a memhandler
3368 save_regs(reglist);
13e35c04 3369 pass_args(rs,rt);
b96d3df7 3370 int cc=get_reg(regmap,CCREG);
3371 if(cc<0)
3372 emit_loadreg(CCREG,2);
2573466a 3373 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
b96d3df7 3374 emit_movimm(handler,3);
3375 // returns new cycle_count
3376 emit_call((int)jump_handler_write_h);
2573466a 3377 emit_addimm(0,-CLOCK_ADJUST(adj+1),cc<0?2:cc);
b96d3df7 3378 if(cc<0)
3379 emit_storereg(CCREG,2);
3380 restore_regs(reglist);
3381#else // if !pcsx
57871462 3382 int ftable=0;
3383 if(type==STOREB_STUB)
3384 ftable=(int)writememb;
3385 if(type==STOREH_STUB)
3386 ftable=(int)writememh;
3387 if(type==STOREW_STUB)
3388 ftable=(int)writemem;
24385cae 3389#ifndef FORCE32
57871462 3390 if(type==STORED_STUB)
3391 ftable=(int)writememd;
24385cae 3392#endif
3393 assert(ftable!=0);
57871462 3394 emit_writeword(rs,(int)&address);
3395 //emit_shrimm(rs,16,rs);
3396 //emit_movmem_indexedx4(ftable,rs,rs);
3397 if(type==STOREB_STUB)
3398 emit_writebyte(rt,(int)&byte);
3399 if(type==STOREH_STUB)
3400 emit_writehword(rt,(int)&hword);
3401 if(type==STOREW_STUB)
3402 emit_writeword(rt,(int)&word);
3403 if(type==STORED_STUB) {
3d624f89 3404#ifndef FORCE32
57871462 3405 emit_writeword(rt,(int)&dword);
3406 emit_writeword(target?rth:rt,(int)&dword+4);
3d624f89 3407#else
c43b5311 3408 SysPrintf("STORED_STUB\n");
3d624f89 3409#endif
57871462 3410 }
3411 //emit_pusha();
3412 save_regs(reglist);
0c1fe38b 3413#ifndef PCSX
3414 // rearmed note: load_all_consts prevents BIOS boot, some bug?
3415 if((signed int)addr>=(signed int)0xC0000000) {
3416 // Theoretically we can have a pagefault here, if the TLB has never
3417 // been enabled and the address is outside the range 80000000..BFFFFFFF
3418 // Write out the registers so the pagefault can be handled. This is
3419 // a very rare case and likely represents a bug.
3420 int ds=regmap!=regs[i].regmap;
3421 if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
3422 if(!ds) wb_dirtys(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty);
3423 else wb_dirtys(branch_regs[i-1].regmap_entry,branch_regs[i-1].was32,branch_regs[i-1].wasdirty);
3424 }
3425#endif
57871462 3426 //emit_shrimm(rs,16,1);
3427 int cc=get_reg(regmap,CCREG);
3428 if(cc<0) {
3429 emit_loadreg(CCREG,2);
3430 }
3431 //emit_movimm(ftable,0);
3432 emit_movimm(((u_int *)ftable)[addr>>16],0);
3433 //emit_readword((int)&last_count,12);
2573466a 3434 emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2);
f51dc36c 3435#ifndef PCSX
57871462 3436 if((signed int)addr>=(signed int)0xC0000000) {
3437 // Pagefault address
3438 int ds=regmap!=regs[i].regmap;
3439 emit_movimm(start+i*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
3440 }
f51dc36c 3441#endif
57871462 3442 //emit_add(12,2,2);
3443 //emit_writeword(2,(int)&Count);
3444 //emit_call(((u_int *)ftable)[addr>>16]);
3445 emit_call((int)&indirect_jump);
3446 emit_readword((int)&Count,HOST_TEMPREG);
3447 emit_readword((int)&next_interupt,2);
2573466a 3448 emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG);
57871462 3449 emit_writeword(2,(int)&last_count);
3450 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
3451 if(cc<0) {
3452 emit_storereg(CCREG,HOST_TEMPREG);
3453 }
3454 //emit_popa();
3455 restore_regs(reglist);
b96d3df7 3456#endif
57871462 3457}
3458
3459do_unalignedwritestub(int n)
3460{
b7918751 3461 assem_debug("do_unalignedwritestub %x\n",start+stubs[n][3]*4);
3462 literal_pool(256);
57871462 3463 set_jump_target(stubs[n][1],(int)out);
b7918751 3464
3465 int i=stubs[n][3];
3466 struct regstat *i_regs=(struct regstat *)stubs[n][4];
3467 int addr=stubs[n][5];
3468 u_int reglist=stubs[n][7];
3469 signed char *i_regmap=i_regs->regmap;
3470 int temp2=get_reg(i_regmap,FTEMP);
3471 int rt;
3472 int ds, real_rs;
3473 rt=get_reg(i_regmap,rs2[i]);
3474 assert(rt>=0);
3475 assert(addr>=0);
3476 assert(opcode[i]==0x2a||opcode[i]==0x2e); // SWL/SWR only implemented
3477 reglist|=(1<<addr);
3478 reglist&=~(1<<temp2);
3479
b96d3df7 3480#if 1
3481 // don't bother with it and call write handler
3482 save_regs(reglist);
3483 pass_args(addr,rt);
3484 int cc=get_reg(i_regmap,CCREG);
3485 if(cc<0)
3486 emit_loadreg(CCREG,2);
2573466a 3487 emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2);
b96d3df7 3488 emit_call((int)(opcode[i]==0x2a?jump_handle_swl:jump_handle_swr));
2573466a 3489 emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc);
b96d3df7 3490 if(cc<0)
3491 emit_storereg(CCREG,2);
3492 restore_regs(reglist);
3493 emit_jmp(stubs[n][2]); // return address
3494#else
b7918751 3495 emit_andimm(addr,0xfffffffc,temp2);
3496 emit_writeword(temp2,(int)&address);
3497
3498 save_regs(reglist);
97a238a6 3499#ifndef PCSX
b7918751 3500 ds=i_regs!=&regs[i];
3501 real_rs=get_reg(i_regmap,rs1[i]);
3502 u_int cmask=ds?-1:(0x100f|~i_regs->wasconst);
3503 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);
3504 wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<<addr)&(real_rs<0?-1:~(1<<real_rs)));
3505 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 3506#endif
b7918751 3507 emit_shrimm(addr,16,1);
3508 int cc=get_reg(i_regmap,CCREG);
3509 if(cc<0) {
3510 emit_loadreg(CCREG,2);
3511 }
3512 emit_movimm((u_int)readmem,0);
3513 emit_addimm(cc<0?2:cc,2*stubs[n][6]+2,2);
f51dc36c 3514#ifndef PCSX
3515 // pagefault address
3516 emit_movimm(start+stubs[n][3]*4+(((regs[i].was32>>rs1[i])&1)<<1)+ds,3);
3517#endif
b7918751 3518 emit_call((int)&indirect_jump_indexed);
3519 restore_regs(reglist);
3520
3521 emit_readword((int)&readmem_dword,temp2);
3522 int temp=addr; //hmh
3523 emit_shlimm(addr,3,temp);
3524 emit_andimm(temp,24,temp);
3525#ifdef BIG_ENDIAN_MIPS
3526 if (opcode[i]==0x2e) // SWR
3527#else
3528 if (opcode[i]==0x2a) // SWL
3529#endif
3530 emit_xorimm(temp,24,temp);
3531 emit_movimm(-1,HOST_TEMPREG);
55439448 3532 if (opcode[i]==0x2a) { // SWL
b7918751 3533 emit_bic_lsr(temp2,HOST_TEMPREG,temp,temp2);
3534 emit_orrshr(rt,temp,temp2);
3535 }else{
3536 emit_bic_lsl(temp2,HOST_TEMPREG,temp,temp2);
3537 emit_orrshl(rt,temp,temp2);
3538 }
3539 emit_readword((int)&address,addr);
3540 emit_writeword(temp2,(int)&word);
3541 //save_regs(reglist); // don't need to, no state changes
3542 emit_shrimm(addr,16,1);
3543 emit_movimm((u_int)writemem,0);
3544 //emit_call((int)&indirect_jump_indexed);
3545 emit_mov(15,14);
3546 emit_readword_dualindexedx4(0,1,15);
3547 emit_readword((int)&Count,HOST_TEMPREG);
3548 emit_readword((int)&next_interupt,2);
3549 emit_addimm(HOST_TEMPREG,-2*stubs[n][6]-2,HOST_TEMPREG);
3550 emit_writeword(2,(int)&last_count);
3551 emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc);
3552 if(cc<0) {
3553 emit_storereg(CCREG,HOST_TEMPREG);
3554 }
3555 restore_regs(reglist);
57871462 3556 emit_jmp(stubs[n][2]); // return address
b96d3df7 3557#endif
57871462 3558}
3559
3560void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a)
3561{
3562 printf("regs: %x %x %x %x %x %x %x (%x)\n",a,b,c,d,ebp,esi,edi,(&edi)[-1]);
3563}
3564
3565do_invstub(int n)
3566{
3567 literal_pool(20);
3568 u_int reglist=stubs[n][3];
3569 set_jump_target(stubs[n][1],(int)out);
3570 save_regs(reglist);
3571 if(stubs[n][4]!=0) emit_mov(stubs[n][4],0);
3572 emit_call((int)&invalidate_addr);
3573 restore_regs(reglist);
3574 emit_jmp(stubs[n][2]); // return address
3575}
3576
3577int do_dirty_stub(int i)
3578{
3579 assem_debug("do_dirty_stub %x\n",start+i*4);
ac545b3a 3580 u_int addr=(int)start<(int)0xC0000000?(u_int)source:(u_int)start;
3581 #ifdef PCSX
3582 addr=(u_int)source;
3583 #endif
57871462 3584 // Careful about the code output here, verify_dirty needs to parse it.
665f33e1 3585 #ifndef HAVE_ARMV7
ac545b3a 3586 emit_loadlp(addr,1);
57871462 3587 emit_loadlp((int)copy,2);
3588 emit_loadlp(slen*4,3);
3589 #else
ac545b3a 3590 emit_movw(addr&0x0000FFFF,1);
57871462 3591 emit_movw(((u_int)copy)&0x0000FFFF,2);
ac545b3a 3592 emit_movt(addr&0xFFFF0000,1);
57871462 3593 emit_movt(((u_int)copy)&0xFFFF0000,2);
3594 emit_movw(slen*4,3);
3595 #endif
3596 emit_movimm(start+i*4,0);
3597 emit_call((int)start<(int)0xC0000000?(int)&verify_code:(int)&verify_code_vm);
3598 int entry=(int)out;
3599 load_regs_entry(i);
3600 if(entry==(int)out) entry=instr_addr[i];
3601 emit_jmp(instr_addr[i]);
3602 return entry;
3603}
3604
3605void do_dirty_stub_ds()
3606{
3607 // Careful about the code output here, verify_dirty needs to parse it.
665f33e1 3608 #ifndef HAVE_ARMV7
57871462 3609 emit_loadlp((int)start<(int)0xC0000000?(int)source:(int)start,1);
3610 emit_loadlp((int)copy,2);
3611 emit_loadlp(slen*4,3);
3612 #else
3613 emit_movw(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0x0000FFFF,1);
3614 emit_movw(((u_int)copy)&0x0000FFFF,2);
3615 emit_movt(((int)start<(int)0xC0000000?(u_int)source:(u_int)start)&0xFFFF0000,1);
3616 emit_movt(((u_int)copy)&0xFFFF0000,2);
3617 emit_movw(slen*4,3);
3618 #endif
3619 emit_movimm(start+1,0);
3620 emit_call((int)&verify_code_ds);
3621}
3622
3623do_cop1stub(int n)
3624{
3625 literal_pool(256);
3626 assem_debug("do_cop1stub %x\n",start+stubs[n][3]*4);
3627 set_jump_target(stubs[n][1],(int)out);
3628 int i=stubs[n][3];
3d624f89 3629// int rs=stubs[n][4];
57871462 3630 struct regstat *i_regs=(struct regstat *)stubs[n][5];
3631 int ds=stubs[n][6];
3632 if(!ds) {
3633 load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,i);
3634 //if(i_regs!=&regs[i]) printf("oops: regs[i]=%x i_regs=%x",(int)&regs[i],(int)i_regs);
3635 }
3636 //else {printf("fp exception in delay slot\n");}
3637 wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty);
3638 if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
3639 emit_movimm(start+(i-ds)*4,EAX); // Get PC
2573466a 3640 emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle...
57871462 3641 emit_jmp(ds?(int)fp_exception_ds:(int)fp_exception);
3642}
3643
63cb0298 3644#ifndef DISABLE_TLB
3645
57871462 3646/* TLB */
3647
3648int do_tlb_r(int s,int ar,int map,int x,int a,int shift,int c,u_int addr)
3649{
3650 if(c) {
3651 if((signed int)addr>=(signed int)0xC0000000) {
3652 // address_generation already loaded the const
3653 emit_readword_dualindexedx4(FP,map,map);
3654 }
3655 else
3656 return -1; // No mapping
3657 }
3658 else {
3659 assert(s!=map);
3660 emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map);
3661 emit_addsr12(map,s,map);
3662 // Schedule this while we wait on the load
3663 //if(x) emit_xorimm(s,x,ar);
3664 if(shift>=0) emit_shlimm(s,3,shift);
3665 if(~a) emit_andimm(s,a,ar);
3666 emit_readword_dualindexedx4(FP,map,map);
3667 }
3668 return map;
3669}
3670int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr)
3671{
3672 if(!c||(signed int)addr>=(signed int)0xC0000000) {
3673 emit_test(map,map);
3674 *jaddr=(int)out;
3675 emit_js(0);
3676 }
3677 return map;
3678}
3679
3680int gen_tlb_addr_r(int ar, int map) {
3681 if(map>=0) {
3682 assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]);
3683 output_w32(0xe0800100|rd_rn_rm(ar,ar,map));
3684 }
3685}
3686
3687int do_tlb_w(int s,int ar,int map,int x,int c,u_int addr)
3688{
3689 if(c) {
3690 if(addr<0x80800000||addr>=0xC0000000) {
3691 // address_generation already loaded the const
3692 emit_readword_dualindexedx4(FP,map,map);
3693 }
3694 else
3695 return -1; // No mapping
3696 }
3697 else {
3698 assert(s!=map);
3699 emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map);
3700 emit_addsr12(map,s,map);
3701 // Schedule this while we wait on the load
3702 //if(x) emit_xorimm(s,x,ar);
3703 emit_readword_dualindexedx4(FP,map,map);
3704 }
3705 return map;
3706}
3707int do_tlb_w_branch(int map, int c, u_int addr, int *jaddr)
3708{
3709 if(!c||addr<0x80800000||addr>=0xC0000000) {
3710 emit_testimm(map,0x40000000);
3711 *jaddr=(int)out;
3712 emit_jne(0);
3713 }
3714}
3715
3716int gen_tlb_addr_w(int ar, int map) {
3717 if(map>=0) {
3718 assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]);
3719 output_w32(0xe0800100|rd_rn_rm(ar,ar,map));
3720 }
3721}
3722
3723// Generate the address of the memory_map entry, relative to dynarec_local
3724generate_map_const(u_int addr,int reg) {
3725 //printf("generate_map_const(%x,%s)\n",addr,regname[reg]);
3726 emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg);
3727}
3728
63cb0298 3729#else
3730
57ab9898 3731static int do_tlb_r(int a, ...) { return 0; }
3732static int do_tlb_r_branch(int a, ...) { return 0; }
3733static int gen_tlb_addr_r(int a, ...) { return 0; }
3734static int do_tlb_w(int a, ...) { return 0; }
3735static int do_tlb_w_branch(int a, ...) { return 0; }
3736static int gen_tlb_addr_w(int a, ...) { return 0; }
63cb0298 3737
3738#endif // DISABLE_TLB
3739
57871462 3740/* Special assem */
3741
3742void shift_assemble_arm(int i,struct regstat *i_regs)
3743{
3744 if(rt1[i]) {
3745 if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV
3746 {
3747 signed char s,t,shift;
3748 t=get_reg(i_regs->regmap,rt1[i]);
3749 s=get_reg(i_regs->regmap,rs1[i]);
3750 shift=get_reg(i_regs->regmap,rs2[i]);
3751 if(t>=0){
3752 if(rs1[i]==0)
3753 {
3754 emit_zeroreg(t);
3755 }
3756 else if(rs2[i]==0)
3757 {
3758 assert(s>=0);
3759 if(s!=t) emit_mov(s,t);
3760 }
3761 else
3762 {
3763 emit_andimm(shift,31,HOST_TEMPREG);
3764 if(opcode2[i]==4) // SLLV
3765 {
3766 emit_shl(s,HOST_TEMPREG,t);
3767 }
3768 if(opcode2[i]==6) // SRLV
3769 {
3770 emit_shr(s,HOST_TEMPREG,t);
3771 }
3772 if(opcode2[i]==7) // SRAV
3773 {
3774 emit_sar(s,HOST_TEMPREG,t);
3775 }
3776 }
3777 }
3778 } else { // DSLLV/DSRLV/DSRAV
3779 signed char sh,sl,th,tl,shift;
3780 th=get_reg(i_regs->regmap,rt1[i]|64);
3781 tl=get_reg(i_regs->regmap,rt1[i]);
3782 sh=get_reg(i_regs->regmap,rs1[i]|64);
3783 sl=get_reg(i_regs->regmap,rs1[i]);
3784 shift=get_reg(i_regs->regmap,rs2[i]);
3785 if(tl>=0){
3786 if(rs1[i]==0)
3787 {
3788 emit_zeroreg(tl);
3789 if(th>=0) emit_zeroreg(th);
3790 }
3791 else if(rs2[i]==0)
3792 {
3793 assert(sl>=0);
3794 if(sl!=tl) emit_mov(sl,tl);
3795 if(th>=0&&sh!=th) emit_mov(sh,th);
3796 }
3797 else
3798 {
3799 // FIXME: What if shift==tl ?
3800 assert(shift!=tl);
3801 int temp=get_reg(i_regs->regmap,-1);
3802 int real_th=th;
3803 if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register
3804 assert(sl>=0);
3805 assert(sh>=0);
3806 emit_andimm(shift,31,HOST_TEMPREG);
3807 if(opcode2[i]==0x14) // DSLLV
3808 {
3809 if(th>=0) emit_shl(sh,HOST_TEMPREG,th);
3810 emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
3811 emit_orrshr(sl,HOST_TEMPREG,th);
3812 emit_andimm(shift,31,HOST_TEMPREG);
3813 emit_testimm(shift,32);
3814 emit_shl(sl,HOST_TEMPREG,tl);
3815 if(th>=0) emit_cmovne_reg(tl,th);
3816 emit_cmovne_imm(0,tl);
3817 }
3818 if(opcode2[i]==0x16) // DSRLV
3819 {
3820 assert(th>=0);
3821 emit_shr(sl,HOST_TEMPREG,tl);
3822 emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
3823 emit_orrshl(sh,HOST_TEMPREG,tl);
3824 emit_andimm(shift,31,HOST_TEMPREG);
3825 emit_testimm(shift,32);
3826 emit_shr(sh,HOST_TEMPREG,th);
3827 emit_cmovne_reg(th,tl);
3828 if(real_th>=0) emit_cmovne_imm(0,th);
3829 }
3830 if(opcode2[i]==0x17) // DSRAV
3831 {
3832 assert(th>=0);
3833 emit_shr(sl,HOST_TEMPREG,tl);
3834 emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG);
3835 if(real_th>=0) {
3836 assert(temp>=0);
3837 emit_sarimm(th,31,temp);
3838 }
3839 emit_orrshl(sh,HOST_TEMPREG,tl);
3840 emit_andimm(shift,31,HOST_TEMPREG);
3841 emit_testimm(shift,32);
3842 emit_sar(sh,HOST_TEMPREG,th);
3843 emit_cmovne_reg(th,tl);
3844 if(real_th>=0) emit_cmovne_reg(temp,th);
3845 }
3846 }
3847 }
3848 }
3849 }
3850}
ffb0b9e0 3851
3852#ifdef PCSX
3853static void speculate_mov(int rs,int rt)
3854{
3855 if(rt!=0) {
3856 smrv_strong_next|=1<<rt;
3857 smrv[rt]=smrv[rs];
3858 }
3859}
3860
3861static void speculate_mov_weak(int rs,int rt)
3862{
3863 if(rt!=0) {
3864 smrv_weak_next|=1<<rt;
3865 smrv[rt]=smrv[rs];
3866 }
3867}
3868
3869static void speculate_register_values(int i)
3870{
3871 if(i==0) {
3872 memcpy(smrv,psxRegs.GPR.r,sizeof(smrv));
3873 // gp,sp are likely to stay the same throughout the block
3874 smrv_strong_next=(1<<28)|(1<<29)|(1<<30);
3875 smrv_weak_next=~smrv_strong_next;
3876 //printf(" llr %08x\n", smrv[4]);
3877 }
3878 smrv_strong=smrv_strong_next;
3879 smrv_weak=smrv_weak_next;
3880 switch(itype[i]) {
3881 case ALU:
3882 if ((smrv_strong>>rs1[i])&1) speculate_mov(rs1[i],rt1[i]);
3883 else if((smrv_strong>>rs2[i])&1) speculate_mov(rs2[i],rt1[i]);
3884 else if((smrv_weak>>rs1[i])&1) speculate_mov_weak(rs1[i],rt1[i]);
3885 else if((smrv_weak>>rs2[i])&1) speculate_mov_weak(rs2[i],rt1[i]);
3886 else {
3887 smrv_strong_next&=~(1<<rt1[i]);
3888 smrv_weak_next&=~(1<<rt1[i]);
3889 }
3890 break;
3891 case SHIFTIMM:
3892 smrv_strong_next&=~(1<<rt1[i]);
3893 smrv_weak_next&=~(1<<rt1[i]);
3894 // fallthrough
3895 case IMM16:
3896 if(rt1[i]&&is_const(&regs[i],rt1[i])) {
3897 int value,hr=get_reg(regs[i].regmap,rt1[i]);
3898 if(hr>=0) {
3899 if(get_final_value(hr,i,&value))
3900 smrv[rt1[i]]=value;
3901 else smrv[rt1[i]]=constmap[i][hr];
3902 smrv_strong_next|=1<<rt1[i];
3903 }
3904 }
3905 else {
3906 if ((smrv_strong>>rs1[i])&1) speculate_mov(rs1[i],rt1[i]);
3907 else if((smrv_weak>>rs1[i])&1) speculate_mov_weak(rs1[i],rt1[i]);
3908 }
3909 break;
3910 case LOAD:
3911 if(start<0x2000&&(rt1[i]==26||(smrv[rt1[i]]>>24)==0xa0)) {
3912 // special case for BIOS
3913 smrv[rt1[i]]=0xa0000000;
3914 smrv_strong_next|=1<<rt1[i];
3915 break;
3916 }
3917 // fallthrough
3918 case SHIFT:
3919 case LOADLR:
3920 case MOV:
3921 smrv_strong_next&=~(1<<rt1[i]);
3922 smrv_weak_next&=~(1<<rt1[i]);
3923 break;
3924 case COP0:
3925 case COP2:
3926 if(opcode2[i]==0||opcode2[i]==2) { // MFC/CFC
3927 smrv_strong_next&=~(1<<rt1[i]);
3928 smrv_weak_next&=~(1<<rt1[i]);
3929 }
3930 break;
3931 case C2LS:
3932 if (opcode[i]==0x32) { // LWC2
3933 smrv_strong_next&=~(1<<rt1[i]);
3934 smrv_weak_next&=~(1<<rt1[i]);
3935 }
3936 break;
3937 }
3938#if 0
3939 int r=4;
3940 printf("x %08x %08x %d %d c %08x %08x\n",smrv[r],start+i*4,
3941 ((smrv_strong>>r)&1),(smrv_weak>>r)&1,regs[i].isconst,regs[i].wasconst);
3942#endif
3943}
3944
3945enum {
3946 MTYPE_8000 = 0,
3947 MTYPE_8020,
3948 MTYPE_0000,
3949 MTYPE_A000,
3950 MTYPE_1F80,
3951};
3952
3953static int get_ptr_mem_type(u_int a)
3954{
3955 if(a < 0x00200000) {
3956 if(a<0x1000&&((start>>20)==0xbfc||(start>>24)==0xa0))
3957 // return wrong, must use memhandler for BIOS self-test to pass
3958 // 007 does similar stuff from a00 mirror, weird stuff
3959 return MTYPE_8000;
3960 return MTYPE_0000;
3961 }
3962 if(0x1f800000 <= a && a < 0x1f801000)
3963 return MTYPE_1F80;
3964 if(0x80200000 <= a && a < 0x80800000)
3965 return MTYPE_8020;
3966 if(0xa0000000 <= a && a < 0xa0200000)
3967 return MTYPE_A000;
3968 return MTYPE_8000;
3969}
3970#endif
3971
3972static int emit_fastpath_cmp_jump(int i,int addr,int *addr_reg_override)
3973{
3974 int jaddr,type=0;
3975
3976#ifdef PCSX
3977 int mr=rs1[i];
3978 if(((smrv_strong|smrv_weak)>>mr)&1) {
3979 type=get_ptr_mem_type(smrv[mr]);
3980 //printf("set %08x @%08x r%d %d\n", smrv[mr], start+i*4, mr, type);
3981 }
3982 else {
3983 // use the mirror we are running on
3984 type=get_ptr_mem_type(start);
3985 //printf("set nospec @%08x r%d %d\n", start+i*4, mr, type);
3986 }
3987
3988 if(type==MTYPE_8020) { // RAM 80200000+ mirror
3989 emit_andimm(addr,~0x00e00000,HOST_TEMPREG);
3990 addr=*addr_reg_override=HOST_TEMPREG;
3991 type=0;
3992 }
3993 else if(type==MTYPE_0000) { // RAM 0 mirror
3994 emit_orimm(addr,0x80000000,HOST_TEMPREG);
3995 addr=*addr_reg_override=HOST_TEMPREG;
3996 type=0;
3997 }
3998 else if(type==MTYPE_A000) { // RAM A mirror
3999 emit_andimm(addr,~0x20000000,HOST_TEMPREG);
4000 addr=*addr_reg_override=HOST_TEMPREG;
4001 type=0;
4002 }
4003 else if(type==MTYPE_1F80) { // scratchpad
6d760c92 4004 if (psxH == (void *)0x1f800000) {
4005 emit_addimm(addr,-0x1f800000,HOST_TEMPREG);
4006 emit_cmpimm(HOST_TEMPREG,0x1000);
4007 jaddr=(int)out;
4008 emit_jc(0);
4009 }
4010 else {
4011 // do usual RAM check, jump will go to the right handler
4012 type=0;
4013 }
ffb0b9e0 4014 }
4015#endif
4016
4017 if(type==0)
4018 {
4019 emit_cmpimm(addr,RAM_SIZE);
4020 jaddr=(int)out;
4021 #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
4022 // Hint to branch predictor that the branch is unlikely to be taken
4023 if(rs1[i]>=28)
4024 emit_jno_unlikely(0);
4025 else
4026 #endif
4027 emit_jno(0);
a327ad27 4028 if(ram_offset!=0) {
4029 emit_addimm(addr,ram_offset,HOST_TEMPREG);
4030 addr=*addr_reg_override=HOST_TEMPREG;
4031 }
ffb0b9e0 4032 }
4033
4034 return jaddr;
4035}
4036
57871462 4037#define shift_assemble shift_assemble_arm
4038
4039void loadlr_assemble_arm(int i,struct regstat *i_regs)
4040{
4041 int s,th,tl,temp,temp2,addr,map=-1;
4042 int offset;
4043 int jaddr=0;
af4ee1fe 4044 int memtarget=0,c=0;
ffb0b9e0 4045 int fastload_reg_override=0;
57871462 4046 u_int hr,reglist=0;
4047 th=get_reg(i_regs->regmap,rt1[i]|64);
4048 tl=get_reg(i_regs->regmap,rt1[i]);
4049 s=get_reg(i_regs->regmap,rs1[i]);
4050 temp=get_reg(i_regs->regmap,-1);
4051 temp2=get_reg(i_regs->regmap,FTEMP);
4052 addr=get_reg(i_regs->regmap,AGEN1+(i&1));
4053 assert(addr<0);
4054 offset=imm[i];
4055 for(hr=0;hr<HOST_REGS;hr++) {
4056 if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
4057 }
4058 reglist|=1<<temp;
4059 if(offset||s<0||c) addr=temp2;
4060 else addr=s;
4061 if(s>=0) {
4062 c=(i_regs->wasconst>>s)&1;
af4ee1fe 4063 if(c) {
4064 memtarget=((signed int)(constmap[i][s]+offset))<(signed int)0x80000000+RAM_SIZE;
4065 if(using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1;
4066 }
57871462 4067 }
535d208a 4068 if(!using_tlb) {
4069 if(!c) {
4070 #ifdef RAM_OFFSET
4071 map=get_reg(i_regs->regmap,ROREG);
4072 if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG);
4073 #endif
4074 emit_shlimm(addr,3,temp);
4075 if (opcode[i]==0x22||opcode[i]==0x26) {
4076 emit_andimm(addr,0xFFFFFFFC,temp2); // LWL/LWR
57871462 4077 }else{
535d208a 4078 emit_andimm(addr,0xFFFFFFF8,temp2); // LDL/LDR
57871462 4079 }
ffb0b9e0 4080 jaddr=emit_fastpath_cmp_jump(i,temp2,&fastload_reg_override);
535d208a 4081 }
4082 else {
a327ad27 4083 if(ram_offset&&memtarget) {
4084 emit_addimm(temp2,ram_offset,HOST_TEMPREG);
4085 fastload_reg_override=HOST_TEMPREG;
4086 }
535d208a 4087 if (opcode[i]==0x22||opcode[i]==0x26) {
4088 emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
4089 }else{
4090 emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
57871462 4091 }
57871462 4092 }
535d208a 4093 }else{ // using tlb
4094 int a;
4095 if(c) {
4096 a=-1;
4097 }else if (opcode[i]==0x22||opcode[i]==0x26) {
4098 a=0xFFFFFFFC; // LWL/LWR
4099 }else{
4100 a=0xFFFFFFF8; // LDL/LDR
4101 }
4102 map=get_reg(i_regs->regmap,TLREG);
4103 assert(map>=0);
ea3d2e6e 4104 reglist&=~(1<<map);
535d208a 4105 map=do_tlb_r(addr,temp2,map,0,a,c?-1:temp,c,constmap[i][s]+offset);
4106 if(c) {
4107 if (opcode[i]==0x22||opcode[i]==0x26) {
4108 emit_movimm(((constmap[i][s]+offset)<<3)&24,temp); // LWL/LWR
4109 }else{
4110 emit_movimm(((constmap[i][s]+offset)<<3)&56,temp); // LDL/LDR
57871462 4111 }
535d208a 4112 }
4113 do_tlb_r_branch(map,c,constmap[i][s]+offset,&jaddr);
4114 }
4115 if (opcode[i]==0x22||opcode[i]==0x26) { // LWL/LWR
4116 if(!c||memtarget) {
ffb0b9e0 4117 int a=temp2;
4118 if(fastload_reg_override) a=fastload_reg_override;
535d208a 4119 //emit_readword_indexed((int)rdram-0x80000000,temp2,temp2);
ffb0b9e0 4120 emit_readword_indexed_tlb(0,a,map,temp2);
535d208a 4121 if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
4122 }
4123 else
4124 inline_readstub(LOADW_STUB,i,(constmap[i][s]+offset)&0xFFFFFFFC,i_regs->regmap,FTEMP,ccadj[i],reglist);
4125 if(rt1[i]) {
4126 assert(tl>=0);
57871462 4127 emit_andimm(temp,24,temp);
2002a1db 4128#ifdef BIG_ENDIAN_MIPS
4129 if (opcode[i]==0x26) // LWR
4130#else
4131 if (opcode[i]==0x22) // LWL
4132#endif
4133 emit_xorimm(temp,24,temp);
57871462 4134 emit_movimm(-1,HOST_TEMPREG);
4135 if (opcode[i]==0x26) {
4136 emit_shr(temp2,temp,temp2);
4137 emit_bic_lsr(tl,HOST_TEMPREG,temp,tl);
4138 }else{
4139 emit_shl(temp2,temp,temp2);
4140 emit_bic_lsl(tl,HOST_TEMPREG,temp,tl);
4141 }
4142 emit_or(temp2,tl,tl);
57871462 4143 }
535d208a 4144 //emit_storereg(rt1[i],tl); // DEBUG
4145 }
4146 if (opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR
ffb0b9e0 4147 // FIXME: little endian, fastload_reg_override
535d208a 4148 int temp2h=get_reg(i_regs->regmap,FTEMP|64);
4149 if(!c||memtarget) {
4150 //if(th>=0) emit_readword_indexed((int)rdram-0x80000000,temp2,temp2h);
4151 //emit_readword_indexed((int)rdram-0x7FFFFFFC,temp2,temp2);
4152 emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2);
4153 if(jaddr) add_stub(LOADD_STUB,jaddr,(int)out,i,temp2,(int)i_regs,ccadj[i],reglist);
4154 }
4155 else
4156 inline_readstub(LOADD_STUB,i,(constmap[i][s]+offset)&0xFFFFFFF8,i_regs->regmap,FTEMP,ccadj[i],reglist);
4157 if(rt1[i]) {
4158 assert(th>=0);
4159 assert(tl>=0);
57871462 4160 emit_testimm(temp,32);
4161 emit_andimm(temp,24,temp);
4162 if (opcode[i]==0x1A) { // LDL
4163 emit_rsbimm(temp,32,HOST_TEMPREG);
4164 emit_shl(temp2h,temp,temp2h);
4165 emit_orrshr(temp2,HOST_TEMPREG,temp2h);
4166 emit_movimm(-1,HOST_TEMPREG);
4167 emit_shl(temp2,temp,temp2);
4168 emit_cmove_reg(temp2h,th);
4169 emit_biceq_lsl(tl,HOST_TEMPREG,temp,tl);
4170 emit_bicne_lsl(th,HOST_TEMPREG,temp,th);
4171 emit_orreq(temp2,tl,tl);
4172 emit_orrne(temp2,th,th);
4173 }
4174 if (opcode[i]==0x1B) { // LDR
4175 emit_xorimm(temp,24,temp);
4176 emit_rsbimm(temp,32,HOST_TEMPREG);
4177 emit_shr(temp2,temp,temp2);
4178 emit_orrshl(temp2h,HOST_TEMPREG,temp2);
4179 emit_movimm(-1,HOST_TEMPREG);
4180 emit_shr(temp2h,temp,temp2h);
4181 emit_cmovne_reg(temp2,tl);
4182 emit_bicne_lsr(th,HOST_TEMPREG,temp,th);
4183 emit_biceq_lsr(tl,HOST_TEMPREG,temp,tl);
4184 emit_orrne(temp2h,th,th);
4185 emit_orreq(temp2h,tl,tl);
4186 }
4187 }
4188 }
4189}
4190#define loadlr_assemble loadlr_assemble_arm
4191
4192void cop0_assemble(int i,struct regstat *i_regs)
4193{
4194 if(opcode2[i]==0) // MFC0
4195 {
4196 signed char t=get_reg(i_regs->regmap,rt1[i]);
4197 char copr=(source[i]>>11)&0x1f;
4198 //assert(t>=0); // Why does this happen? OOT is weird
f1b3b369 4199 if(t>=0&&rt1[i]!=0) {
7139f3c8 4200#ifdef MUPEN64
57871462 4201 emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0);
4202 emit_movimm((source[i]>>11)&0x1f,1);
4203 emit_writeword(0,(int)&PC);
4204 emit_writebyte(1,(int)&(fake_pc.f.r.nrd));
4205 if(copr==9) {
4206 emit_readword((int)&last_count,ECX);
4207 emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
4208 emit_add(HOST_CCREG,ECX,HOST_CCREG);
2573466a 4209 emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
57871462 4210 emit_writeword(HOST_CCREG,(int)&Count);
4211 }
4212 emit_call((int)MFC0);
4213 emit_readword((int)&readmem_dword,t);
7139f3c8 4214#else
4215 emit_readword((int)&reg_cop0+copr*4,t);
4216#endif
57871462 4217 }
4218 }
4219 else if(opcode2[i]==4) // MTC0
4220 {
4221 signed char s=get_reg(i_regs->regmap,rs1[i]);
4222 char copr=(source[i]>>11)&0x1f;
4223 assert(s>=0);
63cb0298 4224#ifdef MUPEN64
57871462 4225 emit_writeword(s,(int)&readmem_dword);
4226 wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32);
4227 emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0);
4228 emit_movimm((source[i]>>11)&0x1f,1);
4229 emit_writeword(0,(int)&PC);
4230 emit_writebyte(1,(int)&(fake_pc.f.r.nrd));
63cb0298 4231#else
4232 wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32);
7139f3c8 4233#endif
4234 if(copr==9||copr==11||copr==12||copr==13) {
63cb0298 4235 emit_readword((int)&last_count,HOST_TEMPREG);
57871462 4236 emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc
63cb0298 4237 emit_add(HOST_CCREG,HOST_TEMPREG,HOST_CCREG);
2573466a 4238 emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
57871462 4239 emit_writeword(HOST_CCREG,(int)&Count);
4240 }
4241 // What a mess. The status register (12) can enable interrupts,
4242 // so needs a special case to handle a pending interrupt.
4243 // The interrupt must be taken immediately, because a subsequent
4244 // instruction might disable interrupts again.
7139f3c8 4245 if(copr==12||copr==13) {
fca1aef2 4246#ifdef PCSX
4247 if (is_delayslot) {
4248 // burn cycles to cause cc_interrupt, which will
4249 // reschedule next_interupt. Relies on CCREG from above.
4250 assem_debug("MTC0 DS %d\n", copr);
4251 emit_writeword(HOST_CCREG,(int)&last_count);
4252 emit_movimm(0,HOST_CCREG);
4253 emit_storereg(CCREG,HOST_CCREG);
caeefe31 4254 emit_loadreg(rs1[i],1);
fca1aef2 4255 emit_movimm(copr,0);
4256 emit_call((int)pcsx_mtc0_ds);
042c7287 4257 emit_loadreg(rs1[i],s);
fca1aef2 4258 return;
4259 }
4260#endif
63cb0298 4261 emit_movimm(start+i*4+4,HOST_TEMPREG);
4262 emit_writeword(HOST_TEMPREG,(int)&pcaddr);
4263 emit_movimm(0,HOST_TEMPREG);
4264 emit_writeword(HOST_TEMPREG,(int)&pending_exception);
57871462 4265 }
4266 //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12);
4267 //else
fca1aef2 4268#ifdef PCSX
caeefe31 4269 if(s==HOST_CCREG)
4270 emit_loadreg(rs1[i],1);
4271 else if(s!=1)
63cb0298 4272 emit_mov(s,1);
fca1aef2 4273 emit_movimm(copr,0);
4274 emit_call((int)pcsx_mtc0);
4275#else
57871462 4276 emit_call((int)MTC0);
fca1aef2 4277#endif
7139f3c8 4278 if(copr==9||copr==11||copr==12||copr==13) {
57871462 4279 emit_readword((int)&Count,HOST_CCREG);
042c7287 4280 emit_readword((int)&next_interupt,HOST_TEMPREG);
2573466a 4281 emit_addimm(HOST_CCREG,-CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
042c7287 4282 emit_sub(HOST_CCREG,HOST_TEMPREG,HOST_CCREG);
4283 emit_writeword(HOST_TEMPREG,(int)&last_count);
57871462 4284 emit_storereg(CCREG,HOST_CCREG);
4285 }
7139f3c8 4286 if(copr==12||copr==13) {
57871462 4287 assert(!is_delayslot);
4288 emit_readword((int)&pending_exception,14);
042c7287 4289 emit_test(14,14);
4290 emit_jne((int)&do_interrupt);
57871462 4291 }
4292 emit_loadreg(rs1[i],s);
4293 if(get_reg(i_regs->regmap,rs1[i]|64)>=0)
4294 emit_loadreg(rs1[i]|64,get_reg(i_regs->regmap,rs1[i]|64));
57871462 4295 cop1_usable=0;
4296 }
4297 else
4298 {
4299 assert(opcode2[i]==0x10);
3d624f89 4300#ifndef DISABLE_TLB
57871462 4301 if((source[i]&0x3f)==0x01) // TLBR
4302 emit_call((int)TLBR);
4303 if((source[i]&0x3f)==0x02) // TLBWI
4304 emit_call((int)TLBWI_new);
4305 if((source[i]&0x3f)==0x06) { // TLBWR
4306 // The TLB entry written by TLBWR is dependent on the count,
4307 // so update the cycle count
4308 emit_readword((int)&last_count,ECX);
4309 if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
4310 emit_add(HOST_CCREG,ECX,HOST_CCREG);
2573466a 4311 emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG);
57871462 4312 emit_writeword(HOST_CCREG,(int)&Count);
4313 emit_call((int)TLBWR_new);
4314 }
4315 if((source[i]&0x3f)==0x08) // TLBP
4316 emit_call((int)TLBP);
3d624f89 4317#endif
576bbd8f 4318#ifdef PCSX
4319 if((source[i]&0x3f)==0x10) // RFE
4320 {
4321 emit_readword((int)&Status,0);
4322 emit_andimm(0,0x3c,1);
4323 emit_andimm(0,~0xf,0);
4324 emit_orrshr_imm(1,2,0);
4325 emit_writeword(0,(int)&Status);
4326 }
4327#else
57871462 4328 if((source[i]&0x3f)==0x18) // ERET
4329 {
4330 int count=ccadj[i];
4331 if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG);
2573466a 4332 emit_addimm(HOST_CCREG,CLOCK_ADJUST(count),HOST_CCREG); // TODO: Should there be an extra cycle here?
57871462 4333 emit_jmp((int)jump_eret);
4334 }
576bbd8f 4335#endif
57871462 4336 }
4337}
4338
b9b61529 4339static void cop2_get_dreg(u_int copr,signed char tl,signed char temp)
4340{
4341 switch (copr) {
4342 case 1:
4343 case 3:
4344 case 5:
4345 case 8:
4346 case 9:
4347 case 10:
4348 case 11:
4349 emit_readword((int)&reg_cop2d[copr],tl);
4350 emit_signextend16(tl,tl);
4351 emit_writeword(tl,(int)&reg_cop2d[copr]); // hmh
4352 break;
4353 case 7:
4354 case 16:
4355 case 17:
4356 case 18:
4357 case 19:
4358 emit_readword((int)&reg_cop2d[copr],tl);
4359 emit_andimm(tl,0xffff,tl);
4360 emit_writeword(tl,(int)&reg_cop2d[copr]);
4361 break;
4362 case 15:
4363 emit_readword((int)&reg_cop2d[14],tl); // SXY2
4364 emit_writeword(tl,(int)&reg_cop2d[copr]);
4365 break;
4366 case 28:
b9b61529 4367 case 29:
4368 emit_readword((int)&reg_cop2d[9],temp);
4369 emit_testimm(temp,0x8000); // do we need this?
4370 emit_andimm(temp,0xf80,temp);
4371 emit_andne_imm(temp,0,temp);
f70d384d 4372 emit_shrimm(temp,7,tl);
b9b61529 4373 emit_readword((int)&reg_cop2d[10],temp);
4374 emit_testimm(temp,0x8000);
4375 emit_andimm(temp,0xf80,temp);
4376 emit_andne_imm(temp,0,temp);
f70d384d 4377 emit_orrshr_imm(temp,2,tl);
b9b61529 4378 emit_readword((int)&reg_cop2d[11],temp);
4379 emit_testimm(temp,0x8000);
4380 emit_andimm(temp,0xf80,temp);
4381 emit_andne_imm(temp,0,temp);
f70d384d 4382 emit_orrshl_imm(temp,3,tl);
b9b61529 4383 emit_writeword(tl,(int)&reg_cop2d[copr]);
4384 break;
4385 default:
4386 emit_readword((int)&reg_cop2d[copr],tl);
4387 break;
4388 }
4389}
4390
4391static void cop2_put_dreg(u_int copr,signed char sl,signed char temp)
4392{
4393 switch (copr) {
4394 case 15:
4395 emit_readword((int)&reg_cop2d[13],temp); // SXY1
4396 emit_writeword(sl,(int)&reg_cop2d[copr]);
4397 emit_writeword(temp,(int)&reg_cop2d[12]); // SXY0
4398 emit_readword((int)&reg_cop2d[14],temp); // SXY2
4399 emit_writeword(sl,(int)&reg_cop2d[14]);
4400 emit_writeword(temp,(int)&reg_cop2d[13]); // SXY1
4401 break;
4402 case 28:
4403 emit_andimm(sl,0x001f,temp);
f70d384d 4404 emit_shlimm(temp,7,temp);
b9b61529 4405 emit_writeword(temp,(int)&reg_cop2d[9]);
4406 emit_andimm(sl,0x03e0,temp);
f70d384d 4407 emit_shlimm(temp,2,temp);
b9b61529 4408 emit_writeword(temp,(int)&reg_cop2d[10]);
4409 emit_andimm(sl,0x7c00,temp);
f70d384d 4410 emit_shrimm(temp,3,temp);
b9b61529 4411 emit_writeword(temp,(int)&reg_cop2d[11]);
4412 emit_writeword(sl,(int)&reg_cop2d[28]);
4413 break;
4414 case 30:
4415 emit_movs(sl,temp);
4416 emit_mvnmi(temp,temp);
665f33e1 4417#ifdef HAVE_ARMV5
b9b61529 4418 emit_clz(temp,temp);
665f33e1 4419#else
4420 emit_movs(temp,HOST_TEMPREG);
4421 emit_movimm(0,temp);
4422 emit_jeq((int)out+4*4);
4423 emit_addpl_imm(temp,1,temp);
4424 emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
4425 emit_jns((int)out-2*4);
4426#endif
b9b61529 4427 emit_writeword(sl,(int)&reg_cop2d[30]);
4428 emit_writeword(temp,(int)&reg_cop2d[31]);
4429 break;
b9b61529 4430 case 31:
4431 break;
4432 default:
4433 emit_writeword(sl,(int)&reg_cop2d[copr]);
4434 break;
4435 }
4436}
4437
4438void cop2_assemble(int i,struct regstat *i_regs)
4439{
4440 u_int copr=(source[i]>>11)&0x1f;
4441 signed char temp=get_reg(i_regs->regmap,-1);
4442 if (opcode2[i]==0) { // MFC2
4443 signed char tl=get_reg(i_regs->regmap,rt1[i]);
f1b3b369 4444 if(tl>=0&&rt1[i]!=0)
b9b61529 4445 cop2_get_dreg(copr,tl,temp);
4446 }
4447 else if (opcode2[i]==4) { // MTC2
4448 signed char sl=get_reg(i_regs->regmap,rs1[i]);
4449 cop2_put_dreg(copr,sl,temp);
4450 }
4451 else if (opcode2[i]==2) // CFC2
4452 {
4453 signed char tl=get_reg(i_regs->regmap,rt1[i]);
f1b3b369 4454 if(tl>=0&&rt1[i]!=0)
b9b61529 4455 emit_readword((int)&reg_cop2c[copr],tl);
4456 }
4457 else if (opcode2[i]==6) // CTC2
4458 {
4459 signed char sl=get_reg(i_regs->regmap,rs1[i]);
4460 switch(copr) {
4461 case 4:
4462 case 12:
4463 case 20:
4464 case 26:
4465 case 27:
4466 case 29:
4467 case 30:
4468 emit_signextend16(sl,temp);
4469 break;
4470 case 31:
4471 //value = value & 0x7ffff000;
4472 //if (value & 0x7f87e000) value |= 0x80000000;
4473 emit_shrimm(sl,12,temp);
4474 emit_shlimm(temp,12,temp);
4475 emit_testimm(temp,0x7f000000);
4476 emit_testeqimm(temp,0x00870000);
4477 emit_testeqimm(temp,0x0000e000);
4478 emit_orrne_imm(temp,0x80000000,temp);
4479 break;
4480 default:
4481 temp=sl;
4482 break;
4483 }
4484 emit_writeword(temp,(int)&reg_cop2c[copr]);
4485 assert(sl>=0);
4486 }
4487}
4488
054175e9 4489static void c2op_prologue(u_int op,u_int reglist)
4490{
4491 save_regs_all(reglist);
82ed88eb 4492#ifdef PCNT
4493 emit_movimm(op,0);
4494 emit_call((int)pcnt_gte_start);
4495#endif
054175e9 4496 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
4497}
4498
4499static void c2op_epilogue(u_int op,u_int reglist)
4500{
82ed88eb 4501#ifdef PCNT
4502 emit_movimm(op,0);
4503 emit_call((int)pcnt_gte_end);
4504#endif
054175e9 4505 restore_regs_all(reglist);
4506}
4507
6c0eefaf 4508static void c2op_call_MACtoIR(int lm,int need_flags)
4509{
4510 if(need_flags)
4511 emit_call((int)(lm?gteMACtoIR_lm1:gteMACtoIR_lm0));
4512 else
4513 emit_call((int)(lm?gteMACtoIR_lm1_nf:gteMACtoIR_lm0_nf));
4514}
4515
4516static void c2op_call_rgb_func(void *func,int lm,int need_ir,int need_flags)
4517{
4518 emit_call((int)func);
4519 // func is C code and trashes r0
4520 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
4521 if(need_flags||need_ir)
4522 c2op_call_MACtoIR(lm,need_flags);
4523 emit_call((int)(need_flags?gteMACtoRGB:gteMACtoRGB_nf));
4524}
4525
054175e9 4526static void c2op_assemble(int i,struct regstat *i_regs)
b9b61529 4527{
4528 signed char temp=get_reg(i_regs->regmap,-1);
4529 u_int c2op=source[i]&0x3f;
6c0eefaf 4530 u_int hr,reglist_full=0,reglist;
054175e9 4531 int need_flags,need_ir;
b9b61529 4532 for(hr=0;hr<HOST_REGS;hr++) {
6c0eefaf 4533 if(i_regs->regmap[hr]>=0) reglist_full|=1<<hr;
b9b61529 4534 }
4d646738 4535 reglist=reglist_full&CALLER_SAVE_REGS;
b9b61529 4536
4537 if (gte_handlers[c2op]!=NULL) {
bedfea38 4538 need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
054175e9 4539 need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
cbbd8dd7 4540 assem_debug("gte op %08x, unneeded %016llx, need_flags %d, need_ir %d\n",
4541 source[i],gte_unneeded[i+1],need_flags,need_ir);
0ff8c62c 4542 if(new_dynarec_hacks&NDHACK_GTE_NO_FLAGS)
4543 need_flags=0;
6c0eefaf 4544 int shift = (source[i] >> 19) & 1;
4545 int lm = (source[i] >> 10) & 1;
054175e9 4546 switch(c2op) {
19776aef 4547#ifndef DRC_DBG
054175e9 4548 case GTE_MVMVA: {
82336ba3 4549#ifdef HAVE_ARMV5
054175e9 4550 int v = (source[i] >> 15) & 3;
4551 int cv = (source[i] >> 13) & 3;
4552 int mx = (source[i] >> 17) & 3;
4d646738 4553 reglist=reglist_full&(CALLER_SAVE_REGS|0xf0); // +{r4-r7}
054175e9 4554 c2op_prologue(c2op,reglist);
4555 /* r4,r5 = VXYZ(v) packed; r6 = &MX11(mx); r7 = &CV1(cv) */
4556 if(v<3)
4557 emit_ldrd(v*8,0,4);
4558 else {
4559 emit_movzwl_indexed(9*4,0,4); // gteIR
4560 emit_movzwl_indexed(10*4,0,6);
4561 emit_movzwl_indexed(11*4,0,5);
4562 emit_orrshl_imm(6,16,4);
4563 }
4564 if(mx<3)
4565 emit_addimm(0,32*4+mx*8*4,6);
4566 else
4567 emit_readword((int)&zeromem_ptr,6);
4568 if(cv<3)
4569 emit_addimm(0,32*4+(cv*8+5)*4,7);
4570 else
4571 emit_readword((int)&zeromem_ptr,7);
4572#ifdef __ARM_NEON__
4573 emit_movimm(source[i],1); // opcode
4574 emit_call((int)gteMVMVA_part_neon);
4575 if(need_flags) {
4576 emit_movimm(lm,1);
4577 emit_call((int)gteMACtoIR_flags_neon);
4578 }
4579#else
4580 if(cv==3&&shift)
4581 emit_call((int)gteMVMVA_part_cv3sh12_arm);
4582 else {
4583 emit_movimm(shift,1);
4584 emit_call((int)(need_flags?gteMVMVA_part_arm:gteMVMVA_part_nf_arm));
4585 }
6c0eefaf 4586 if(need_flags||need_ir)
4587 c2op_call_MACtoIR(lm,need_flags);
82336ba3 4588#endif
4589#else /* if not HAVE_ARMV5 */
4590 c2op_prologue(c2op,reglist);
4591 emit_movimm(source[i],1); // opcode
4592 emit_writeword(1,(int)&psxRegs.code);
4593 emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]));
054175e9 4594#endif
4595 break;
4596 }
6c0eefaf 4597 case GTE_OP:
4598 c2op_prologue(c2op,reglist);
4599 emit_call((int)(shift?gteOP_part_shift:gteOP_part_noshift));
4600 if(need_flags||need_ir) {
4601 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
4602 c2op_call_MACtoIR(lm,need_flags);
4603 }
4604 break;
4605 case GTE_DPCS:
4606 c2op_prologue(c2op,reglist);
4607 c2op_call_rgb_func(shift?gteDPCS_part_shift:gteDPCS_part_noshift,lm,need_ir,need_flags);
4608 break;
4609 case GTE_INTPL:
4610 c2op_prologue(c2op,reglist);
4611 c2op_call_rgb_func(shift?gteINTPL_part_shift:gteINTPL_part_noshift,lm,need_ir,need_flags);
4612 break;
4613 case GTE_SQR:
4614 c2op_prologue(c2op,reglist);
4615 emit_call((int)(shift?gteSQR_part_shift:gteSQR_part_noshift));
4616 if(need_flags||need_ir) {
4617 emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0);
4618 c2op_call_MACtoIR(lm,need_flags);
4619 }
4620 break;
4621 case GTE_DCPL:
4622 c2op_prologue(c2op,reglist);
4623 c2op_call_rgb_func(gteDCPL_part,lm,need_ir,need_flags);
4624 break;
4625 case GTE_GPF:
4626 c2op_prologue(c2op,reglist);
4627 c2op_call_rgb_func(shift?gteGPF_part_shift:gteGPF_part_noshift,lm,need_ir,need_flags);
4628 break;
4629 case GTE_GPL:
4630 c2op_prologue(c2op,reglist);
4631 c2op_call_rgb_func(shift?gteGPL_part_shift:gteGPL_part_noshift,lm,need_ir,need_flags);
4632 break;
19776aef 4633#endif
054175e9 4634 default:
054175e9 4635 c2op_prologue(c2op,reglist);
19776aef 4636#ifdef DRC_DBG
4637 emit_movimm(source[i],1); // opcode
4638 emit_writeword(1,(int)&psxRegs.code);
4639#endif
054175e9 4640 emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]));
4641 break;
4642 }
4643 c2op_epilogue(c2op,reglist);
4644 }
b9b61529 4645}
4646
4647void cop1_unusable(int i,struct regstat *i_regs)
3d624f89 4648{
4649 // XXX: should just just do the exception instead
4650 if(!cop1_usable) {
4651 int jaddr=(int)out;
4652 emit_jmp(0);
4653 add_stub(FP_STUB,jaddr,(int)out,i,0,(int)i_regs,is_delayslot,0);
4654 cop1_usable=1;
4655 }
4656}
4657
57871462 4658void cop1_assemble(int i,struct regstat *i_regs)
4659{
3d624f89 4660#ifndef DISABLE_COP1
57871462 4661 // Check cop1 unusable
4662 if(!cop1_usable) {
4663 signed char rs=get_reg(i_regs->regmap,CSREG);
4664 assert(rs>=0);
4665 emit_testimm(rs,0x20000000);
4666 int jaddr=(int)out;
4667 emit_jeq(0);
4668 add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0);
4669 cop1_usable=1;
4670 }
4671 if (opcode2[i]==0) { // MFC1
4672 signed char tl=get_reg(i_regs->regmap,rt1[i]);
4673 if(tl>=0) {
4674 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],tl);
4675 emit_readword_indexed(0,tl,tl);
4676 }
4677 }
4678 else if (opcode2[i]==1) { // DMFC1
4679 signed char tl=get_reg(i_regs->regmap,rt1[i]);
4680 signed char th=get_reg(i_regs->regmap,rt1[i]|64);
4681 if(tl>=0) {
4682 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],tl);
4683 if(th>=0) emit_readword_indexed(4,tl,th);
4684 emit_readword_indexed(0,tl,tl);
4685 }
4686 }
4687 else if (opcode2[i]==4) { // MTC1
4688 signed char sl=get_reg(i_regs->regmap,rs1[i]);
4689 signed char temp=get_reg(i_regs->regmap,-1);
4690 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
4691 emit_writeword_indexed(sl,0,temp);
4692 }
4693 else if (opcode2[i]==5) { // DMTC1
4694 signed char sl=get_reg(i_regs->regmap,rs1[i]);
4695 signed char sh=rs1[i]>0?get_reg(i_regs->regmap,rs1[i]|64):sl;
4696 signed char temp=get_reg(i_regs->regmap,-1);
4697 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
4698 emit_writeword_indexed(sh,4,temp);
4699 emit_writeword_indexed(sl,0,temp);
4700 }
4701 else if (opcode2[i]==2) // CFC1
4702 {
4703 signed char tl=get_reg(i_regs->regmap,rt1[i]);
4704 if(tl>=0) {
4705 u_int copr=(source[i]>>11)&0x1f;
4706 if(copr==0) emit_readword((int)&FCR0,tl);
4707 if(copr==31) emit_readword((int)&FCR31,tl);
4708 }
4709 }
4710 else if (opcode2[i]==6) // CTC1
4711 {
4712 signed char sl=get_reg(i_regs->regmap,rs1[i]);
4713 u_int copr=(source[i]>>11)&0x1f;
4714 assert(sl>=0);
4715 if(copr==31)
4716 {
4717 emit_writeword(sl,(int)&FCR31);
4718 // Set the rounding mode
4719 //FIXME
4720 //char temp=get_reg(i_regs->regmap,-1);
4721 //emit_andimm(sl,3,temp);
4722 //emit_fldcw_indexed((int)&rounding_modes,temp);
4723 }
4724 }
3d624f89 4725#else
4726 cop1_unusable(i, i_regs);
4727#endif
57871462 4728}
4729
4730void fconv_assemble_arm(int i,struct regstat *i_regs)
4731{
3d624f89 4732#ifndef DISABLE_COP1
57871462 4733 signed char temp=get_reg(i_regs->regmap,-1);
4734 assert(temp>=0);
4735 // Check cop1 unusable
4736 if(!cop1_usable) {
4737 signed char rs=get_reg(i_regs->regmap,CSREG);
4738 assert(rs>=0);
4739 emit_testimm(rs,0x20000000);
4740 int jaddr=(int)out;
4741 emit_jeq(0);
4742 add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0);
4743 cop1_usable=1;
4744 }
4745
4746 #if(defined(__VFP_FP__) && !defined(__SOFTFP__))
4747 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { // trunc_w_s
4748 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
4749 emit_flds(temp,15);
4750 emit_ftosizs(15,15); // float->int, truncate
4751 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f))
4752 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
4753 emit_fsts(15,temp);
4754 return;
4755 }
4756 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { // trunc_w_d
4757 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
4758 emit_vldr(temp,7);
4759 emit_ftosizd(7,13); // double->int, truncate
4760 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
4761 emit_fsts(13,temp);
4762 return;
4763 }
4764
4765 if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { // cvt_s_w
4766 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
4767 emit_flds(temp,13);
4768 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f))
4769 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
4770 emit_fsitos(13,15);
4771 emit_fsts(15,temp);
4772 return;
4773 }
4774 if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { // cvt_d_w
4775 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
4776 emit_flds(temp,13);
4777 emit_readword((int)&reg_cop1_double[(source[i]>>6)&0x1f],temp);
4778 emit_fsitod(13,7);
4779 emit_vstr(7,temp);
4780 return;
4781 }
4782
4783 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { // cvt_d_s
4784 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
4785 emit_flds(temp,13);
4786 emit_readword((int)&reg_cop1_double[(source[i]>>6)&0x1f],temp);
4787 emit_fcvtds(13,7);
4788 emit_vstr(7,temp);
4789 return;
4790 }
4791 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { // cvt_s_d
4792 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
4793 emit_vldr(temp,7);
4794 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
4795 emit_fcvtsd(7,13);
4796 emit_fsts(13,temp);
4797 return;
4798 }
4799 #endif
4800
4801 // C emulation code
4802
4803 u_int hr,reglist=0;
4804 for(hr=0;hr<HOST_REGS;hr++) {
4805 if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
4806 }
4807 save_regs(reglist);
4808
4809 if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) {
4810 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4811 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4812 emit_call((int)cvt_s_w);
4813 }
4814 if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) {
4815 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4816 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4817 emit_call((int)cvt_d_w);
4818 }
4819 if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) {
4820 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4821 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4822 emit_call((int)cvt_s_l);
4823 }
4824 if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) {
4825 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4826 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4827 emit_call((int)cvt_d_l);
4828 }
4829
4830 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) {
4831 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4832 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4833 emit_call((int)cvt_d_s);
4834 }
4835 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) {
4836 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4837 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4838 emit_call((int)cvt_w_s);
4839 }
4840 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) {
4841 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4842 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4843 emit_call((int)cvt_l_s);
4844 }
4845
4846 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) {
4847 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4848 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4849 emit_call((int)cvt_s_d);
4850 }
4851 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) {
4852 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4853 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4854 emit_call((int)cvt_w_d);
4855 }
4856 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) {
4857 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4858 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4859 emit_call((int)cvt_l_d);
4860 }
4861
4862 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) {
4863 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4864 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4865 emit_call((int)round_l_s);
4866 }
4867 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) {
4868 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4869 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4870 emit_call((int)trunc_l_s);
4871 }
4872 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) {
4873 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4874 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4875 emit_call((int)ceil_l_s);
4876 }
4877 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) {
4878 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4879 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4880 emit_call((int)floor_l_s);
4881 }
4882 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) {
4883 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4884 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4885 emit_call((int)round_w_s);
4886 }
4887 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) {
4888 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4889 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4890 emit_call((int)trunc_w_s);
4891 }
4892 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) {
4893 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4894 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4895 emit_call((int)ceil_w_s);
4896 }
4897 if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) {
4898 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
4899 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4900 emit_call((int)floor_w_s);
4901 }
4902
4903 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) {
4904 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4905 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4906 emit_call((int)round_l_d);
4907 }
4908 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) {
4909 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4910 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4911 emit_call((int)trunc_l_d);
4912 }
4913 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) {
4914 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4915 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4916 emit_call((int)ceil_l_d);
4917 }
4918 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) {
4919 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4920 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
4921 emit_call((int)floor_l_d);
4922 }
4923 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) {
4924 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4925 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4926 emit_call((int)round_w_d);
4927 }
4928 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) {
4929 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4930 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4931 emit_call((int)trunc_w_d);
4932 }
4933 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) {
4934 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4935 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4936 emit_call((int)ceil_w_d);
4937 }
4938 if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) {
4939 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
4940 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
4941 emit_call((int)floor_w_d);
4942 }
4943
4944 restore_regs(reglist);
3d624f89 4945#else
4946 cop1_unusable(i, i_regs);
4947#endif
57871462 4948}
4949#define fconv_assemble fconv_assemble_arm
4950
4951void fcomp_assemble(int i,struct regstat *i_regs)
4952{
3d624f89 4953#ifndef DISABLE_COP1
57871462 4954 signed char fs=get_reg(i_regs->regmap,FSREG);
4955 signed char temp=get_reg(i_regs->regmap,-1);
4956 assert(temp>=0);
4957 // Check cop1 unusable
4958 if(!cop1_usable) {
4959 signed char cs=get_reg(i_regs->regmap,CSREG);
4960 assert(cs>=0);
4961 emit_testimm(cs,0x20000000);
4962 int jaddr=(int)out;
4963 emit_jeq(0);
4964 add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0);
4965 cop1_usable=1;
4966 }
4967
4968 if((source[i]&0x3f)==0x30) {
4969 emit_andimm(fs,~0x800000,fs);
4970 return;
4971 }
4972
4973 if((source[i]&0x3e)==0x38) {
4974 // sf/ngle - these should throw exceptions for NaNs
4975 emit_andimm(fs,~0x800000,fs);
4976 return;
4977 }
4978
4979 #if(defined(__VFP_FP__) && !defined(__SOFTFP__))
4980 if(opcode2[i]==0x10) {
4981 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
4982 emit_readword((int)&reg_cop1_simple[(source[i]>>16)&0x1f],HOST_TEMPREG);
4983 emit_orimm(fs,0x800000,fs);
4984 emit_flds(temp,14);
4985 emit_flds(HOST_TEMPREG,15);
4986 emit_fcmps(14,15);
4987 emit_fmstat();
4988 if((source[i]&0x3f)==0x31) emit_bicvc_imm(fs,0x800000,fs); // c_un_s
4989 if((source[i]&0x3f)==0x32) emit_bicne_imm(fs,0x800000,fs); // c_eq_s
4990 if((source[i]&0x3f)==0x33) {emit_bicne_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ueq_s
4991 if((source[i]&0x3f)==0x34) emit_biccs_imm(fs,0x800000,fs); // c_olt_s
4992 if((source[i]&0x3f)==0x35) {emit_biccs_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ult_s
4993 if((source[i]&0x3f)==0x36) emit_bichi_imm(fs,0x800000,fs); // c_ole_s
4994 if((source[i]&0x3f)==0x37) {emit_bichi_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ule_s
4995 if((source[i]&0x3f)==0x3a) emit_bicne_imm(fs,0x800000,fs); // c_seq_s
4996 if((source[i]&0x3f)==0x3b) emit_bicne_imm(fs,0x800000,fs); // c_ngl_s
4997 if((source[i]&0x3f)==0x3c) emit_biccs_imm(fs,0x800000,fs); // c_lt_s
4998 if((source[i]&0x3f)==0x3d) emit_biccs_imm(fs,0x800000,fs); // c_nge_s
4999 if((source[i]&0x3f)==0x3e) emit_bichi_imm(fs,0x800000,fs); // c_le_s
5000 if((source[i]&0x3f)==0x3f) emit_bichi_imm(fs,0x800000,fs); // c_ngt_s
5001 return;
5002 }
5003 if(opcode2[i]==0x11) {
5004 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
5005 emit_readword((int)&reg_cop1_double[(source[i]>>16)&0x1f],HOST_TEMPREG);
5006 emit_orimm(fs,0x800000,fs);
5007 emit_vldr(temp,6);
5008 emit_vldr(HOST_TEMPREG,7);
5009 emit_fcmpd(6,7);
5010 emit_fmstat();
5011 if((source[i]&0x3f)==0x31) emit_bicvc_imm(fs,0x800000,fs); // c_un_d
5012 if((source[i]&0x3f)==0x32) emit_bicne_imm(fs,0x800000,fs); // c_eq_d
5013 if((source[i]&0x3f)==0x33) {emit_bicne_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ueq_d
5014 if((source[i]&0x3f)==0x34) emit_biccs_imm(fs,0x800000,fs); // c_olt_d
5015 if((source[i]&0x3f)==0x35) {emit_biccs_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ult_d
5016 if((source[i]&0x3f)==0x36) emit_bichi_imm(fs,0x800000,fs); // c_ole_d
5017 if((source[i]&0x3f)==0x37) {emit_bichi_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ule_d
5018 if((source[i]&0x3f)==0x3a) emit_bicne_imm(fs,0x800000,fs); // c_seq_d
5019 if((source[i]&0x3f)==0x3b) emit_bicne_imm(fs,0x800000,fs); // c_ngl_d
5020 if((source[i]&0x3f)==0x3c) emit_biccs_imm(fs,0x800000,fs); // c_lt_d
5021 if((source[i]&0x3f)==0x3d) emit_biccs_imm(fs,0x800000,fs); // c_nge_d
5022 if((source[i]&0x3f)==0x3e) emit_bichi_imm(fs,0x800000,fs); // c_le_d
5023 if((source[i]&0x3f)==0x3f) emit_bichi_imm(fs,0x800000,fs); // c_ngt_d
5024 return;
5025 }
5026 #endif
5027
5028 // C only
5029
5030 u_int hr,reglist=0;
5031 for(hr=0;hr<HOST_REGS;hr++) {
5032 if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
5033 }
5034 reglist&=~(1<<fs);
5035 save_regs(reglist);
5036 if(opcode2[i]==0x10) {
5037 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
5038 emit_readword((int)&reg_cop1_simple[(source[i]>>16)&0x1f],ARG2_REG);
5039 if((source[i]&0x3f)==0x30) emit_call((int)c_f_s);
5040 if((source[i]&0x3f)==0x31) emit_call((int)c_un_s);
5041 if((source[i]&0x3f)==0x32) emit_call((int)c_eq_s);
5042 if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_s);
5043 if((source[i]&0x3f)==0x34) emit_call((int)c_olt_s);
5044 if((source[i]&0x3f)==0x35) emit_call((int)c_ult_s);
5045 if((source[i]&0x3f)==0x36) emit_call((int)c_ole_s);
5046 if((source[i]&0x3f)==0x37) emit_call((int)c_ule_s);
5047 if((source[i]&0x3f)==0x38) emit_call((int)c_sf_s);
5048 if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_s);
5049 if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_s);
5050 if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_s);
5051 if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_s);
5052 if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_s);
5053 if((source[i]&0x3f)==0x3e) emit_call((int)c_le_s);
5054 if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_s);
5055 }
5056 if(opcode2[i]==0x11) {
5057 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
5058 emit_readword((int)&reg_cop1_double[(source[i]>>16)&0x1f],ARG2_REG);
5059 if((source[i]&0x3f)==0x30) emit_call((int)c_f_d);
5060 if((source[i]&0x3f)==0x31) emit_call((int)c_un_d);
5061 if((source[i]&0x3f)==0x32) emit_call((int)c_eq_d);
5062 if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_d);
5063 if((source[i]&0x3f)==0x34) emit_call((int)c_olt_d);
5064 if((source[i]&0x3f)==0x35) emit_call((int)c_ult_d);
5065 if((source[i]&0x3f)==0x36) emit_call((int)c_ole_d);
5066 if((source[i]&0x3f)==0x37) emit_call((int)c_ule_d);
5067 if((source[i]&0x3f)==0x38) emit_call((int)c_sf_d);
5068 if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_d);
5069 if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_d);
5070 if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_d);
5071 if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_d);
5072 if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_d);
5073 if((source[i]&0x3f)==0x3e) emit_call((int)c_le_d);
5074 if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_d);
5075 }
5076 restore_regs(reglist);
5077 emit_loadreg(FSREG,fs);
3d624f89 5078#else
5079 cop1_unusable(i, i_regs);
5080#endif
57871462 5081}
5082
5083void float_assemble(int i,struct regstat *i_regs)
5084{
3d624f89 5085#ifndef DISABLE_COP1
57871462 5086 signed char temp=get_reg(i_regs->regmap,-1);
5087 assert(temp>=0);
5088 // Check cop1 unusable
5089 if(!cop1_usable) {
5090 signed char cs=get_reg(i_regs->regmap,CSREG);
5091 assert(cs>=0);
5092 emit_testimm(cs,0x20000000);
5093 int jaddr=(int)out;
5094 emit_jeq(0);
5095 add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0);
5096 cop1_usable=1;
5097 }
5098
5099 #if(defined(__VFP_FP__) && !defined(__SOFTFP__))
5100 if((source[i]&0x3f)==6) // mov
5101 {
5102 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5103 if(opcode2[i]==0x10) {
5104 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
5105 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],HOST_TEMPREG);
5106 emit_readword_indexed(0,temp,temp);
5107 emit_writeword_indexed(temp,0,HOST_TEMPREG);
5108 }
5109 if(opcode2[i]==0x11) {
5110 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
5111 emit_readword((int)&reg_cop1_double[(source[i]>>6)&0x1f],HOST_TEMPREG);
5112 emit_vldr(temp,7);
5113 emit_vstr(7,HOST_TEMPREG);
5114 }
5115 }
5116 return;
5117 }
5118
5119 if((source[i]&0x3f)>3)
5120 {
5121 if(opcode2[i]==0x10) {
5122 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
5123 emit_flds(temp,15);
5124 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5125 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
5126 }
5127 if((source[i]&0x3f)==4) // sqrt
5128 emit_fsqrts(15,15);
5129 if((source[i]&0x3f)==5) // abs
5130 emit_fabss(15,15);
5131 if((source[i]&0x3f)==7) // neg
5132 emit_fnegs(15,15);
5133 emit_fsts(15,temp);
5134 }
5135 if(opcode2[i]==0x11) {
5136 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
5137 emit_vldr(temp,7);
5138 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5139 emit_readword((int)&reg_cop1_double[(source[i]>>6)&0x1f],temp);
5140 }
5141 if((source[i]&0x3f)==4) // sqrt
5142 emit_fsqrtd(7,7);
5143 if((source[i]&0x3f)==5) // abs
5144 emit_fabsd(7,7);
5145 if((source[i]&0x3f)==7) // neg
5146 emit_fnegd(7,7);
5147 emit_vstr(7,temp);
5148 }
5149 return;
5150 }
5151 if((source[i]&0x3f)<4)
5152 {
5153 if(opcode2[i]==0x10) {
5154 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],temp);
5155 }
5156 if(opcode2[i]==0x11) {
5157 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],temp);
5158 }
5159 if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) {
5160 if(opcode2[i]==0x10) {
5161 emit_readword((int)&reg_cop1_simple[(source[i]>>16)&0x1f],HOST_TEMPREG);
5162 emit_flds(temp,15);
5163 emit_flds(HOST_TEMPREG,13);
5164 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5165 if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) {
5166 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
5167 }
5168 }
5169 if((source[i]&0x3f)==0) emit_fadds(15,13,15);
5170 if((source[i]&0x3f)==1) emit_fsubs(15,13,15);
5171 if((source[i]&0x3f)==2) emit_fmuls(15,13,15);
5172 if((source[i]&0x3f)==3) emit_fdivs(15,13,15);
5173 if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) {
5174 emit_fsts(15,HOST_TEMPREG);
5175 }else{
5176 emit_fsts(15,temp);
5177 }
5178 }
5179 else if(opcode2[i]==0x11) {
5180 emit_readword((int)&reg_cop1_double[(source[i]>>16)&0x1f],HOST_TEMPREG);
5181 emit_vldr(temp,7);
5182 emit_vldr(HOST_TEMPREG,6);
5183 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5184 if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) {
5185 emit_readword((int)&reg_cop1_double[(source[i]>>6)&0x1f],temp);
5186 }
5187 }
5188 if((source[i]&0x3f)==0) emit_faddd(7,6,7);
5189 if((source[i]&0x3f)==1) emit_fsubd(7,6,7);
5190 if((source[i]&0x3f)==2) emit_fmuld(7,6,7);
5191 if((source[i]&0x3f)==3) emit_fdivd(7,6,7);
5192 if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) {
5193 emit_vstr(7,HOST_TEMPREG);
5194 }else{
5195 emit_vstr(7,temp);
5196 }
5197 }
5198 }
5199 else {
5200 if(opcode2[i]==0x10) {
5201 emit_flds(temp,15);
5202 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5203 emit_readword((int)&reg_cop1_simple[(source[i]>>6)&0x1f],temp);
5204 }
5205 if((source[i]&0x3f)==0) emit_fadds(15,15,15);
5206 if((source[i]&0x3f)==1) emit_fsubs(15,15,15);
5207 if((source[i]&0x3f)==2) emit_fmuls(15,15,15);
5208 if((source[i]&0x3f)==3) emit_fdivs(15,15,15);
5209 emit_fsts(15,temp);
5210 }
5211 else if(opcode2[i]==0x11) {
5212 emit_vldr(temp,7);
5213 if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) {
5214 emit_readword((int)&reg_cop1_double[(source[i]>>6)&0x1f],temp);
5215 }
5216 if((source[i]&0x3f)==0) emit_faddd(7,7,7);
5217 if((source[i]&0x3f)==1) emit_fsubd(7,7,7);
5218 if((source[i]&0x3f)==2) emit_fmuld(7,7,7);
5219 if((source[i]&0x3f)==3) emit_fdivd(7,7,7);
5220 emit_vstr(7,temp);
5221 }
5222 }
5223 return;
5224 }
5225 #endif
5226
5227 u_int hr,reglist=0;
5228 for(hr=0;hr<HOST_REGS;hr++) {
5229 if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
5230 }
5231 if(opcode2[i]==0x10) { // Single precision
5232 save_regs(reglist);
5233 emit_readword((int)&reg_cop1_simple[(source[i]>>11)&0x1f],ARG1_REG);
5234 if((source[i]&0x3f)<4) {
5235 emit_readword((int)&reg_cop1_simple[(source[i]>>16)&0x1f],ARG2_REG);
5236 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG3_REG);
5237 }else{
5238 emit_readword((int)&reg_cop1_simple[(source[i]>> 6)&0x1f],ARG2_REG);
5239 }
5240 switch(source[i]&0x3f)
5241 {
5242 case 0x00: emit_call((int)add_s);break;
5243 case 0x01: emit_call((int)sub_s);break;
5244 case 0x02: emit_call((int)mul_s);break;
5245 case 0x03: emit_call((int)div_s);break;
5246 case 0x04: emit_call((int)sqrt_s);break;
5247 case 0x05: emit_call((int)abs_s);break;
5248 case 0x06: emit_call((int)mov_s);break;
5249 case 0x07: emit_call((int)neg_s);break;
5250 }
5251 restore_regs(reglist);
5252 }
5253 if(opcode2[i]==0x11) { // Double precision
5254 save_regs(reglist);
5255 emit_readword((int)&reg_cop1_double[(source[i]>>11)&0x1f],ARG1_REG);
5256 if((source[i]&0x3f)<4) {
5257 emit_readword((int)&reg_cop1_double[(source[i]>>16)&0x1f],ARG2_REG);
5258 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG3_REG);
5259 }else{
5260 emit_readword((int)&reg_cop1_double[(source[i]>> 6)&0x1f],ARG2_REG);
5261 }
5262 switch(source[i]&0x3f)
5263 {
5264 case 0x00: emit_call((int)add_d);break;
5265 case 0x01: emit_call((int)sub_d);break;
5266 case 0x02: emit_call((int)mul_d);break;
5267 case 0x03: emit_call((int)div_d);break;
5268 case 0x04: emit_call((int)sqrt_d);break;
5269 case 0x05: emit_call((int)abs_d);break;
5270 case 0x06: emit_call((int)mov_d);break;
5271 case 0x07: emit_call((int)neg_d);break;
5272 }
5273 restore_regs(reglist);
5274 }
3d624f89 5275#else
5276 cop1_unusable(i, i_regs);
5277#endif
57871462 5278}
5279
5280void multdiv_assemble_arm(int i,struct regstat *i_regs)
5281{
5282 // case 0x18: MULT
5283 // case 0x19: MULTU
5284 // case 0x1A: DIV
5285 // case 0x1B: DIVU
5286 // case 0x1C: DMULT
5287 // case 0x1D: DMULTU
5288 // case 0x1E: DDIV
5289 // case 0x1F: DDIVU
5290 if(rs1[i]&&rs2[i])
5291 {
5292 if((opcode2[i]&4)==0) // 32-bit
5293 {
5294 if(opcode2[i]==0x18) // MULT
5295 {
5296 signed char m1=get_reg(i_regs->regmap,rs1[i]);
5297 signed char m2=get_reg(i_regs->regmap,rs2[i]);
5298 signed char hi=get_reg(i_regs->regmap,HIREG);
5299 signed char lo=get_reg(i_regs->regmap,LOREG);
5300 assert(m1>=0);
5301 assert(m2>=0);
5302 assert(hi>=0);
5303 assert(lo>=0);
5304 emit_smull(m1,m2,hi,lo);
5305 }
5306 if(opcode2[i]==0x19) // MULTU
5307 {
5308 signed char m1=get_reg(i_regs->regmap,rs1[i]);
5309 signed char m2=get_reg(i_regs->regmap,rs2[i]);
5310 signed char hi=get_reg(i_regs->regmap,HIREG);
5311 signed char lo=get_reg(i_regs->regmap,LOREG);
5312 assert(m1>=0);
5313 assert(m2>=0);
5314 assert(hi>=0);
5315 assert(lo>=0);
5316 emit_umull(m1,m2,hi,lo);
5317 }
5318 if(opcode2[i]==0x1A) // DIV
5319 {
5320 signed char d1=get_reg(i_regs->regmap,rs1[i]);
5321 signed char d2=get_reg(i_regs->regmap,rs2[i]);
5322 assert(d1>=0);
5323 assert(d2>=0);
5324 signed char quotient=get_reg(i_regs->regmap,LOREG);
5325 signed char remainder=get_reg(i_regs->regmap,HIREG);
5326 assert(quotient>=0);
5327 assert(remainder>=0);
5328 emit_movs(d1,remainder);
44a80f6a 5329 emit_movimm(0xffffffff,quotient);
5330 emit_negmi(quotient,quotient); // .. quotient and ..
5331 emit_negmi(remainder,remainder); // .. remainder for div0 case (will be negated back after jump)
57871462 5332 emit_movs(d2,HOST_TEMPREG);
5333 emit_jeq((int)out+52); // Division by zero
82336ba3 5334 emit_negsmi(HOST_TEMPREG,HOST_TEMPREG);
665f33e1 5335#ifdef HAVE_ARMV5
57871462 5336 emit_clz(HOST_TEMPREG,quotient);
5337 emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG);
665f33e1 5338#else
5339 emit_movimm(0,quotient);
5340 emit_addpl_imm(quotient,1,quotient);
5341 emit_lslpls_imm(HOST_TEMPREG,1,HOST_TEMPREG);
5342 emit_jns((int)out-2*4);
5343#endif
57871462 5344 emit_orimm(quotient,1<<31,quotient);
5345 emit_shr(quotient,quotient,quotient);
5346 emit_cmp(remainder,HOST_TEMPREG);
5347 emit_subcs(remainder,HOST_TEMPREG,remainder);
5348 emit_adcs(quotient,quotient,quotient);
5349 emit_shrimm(HOST_TEMPREG,1,HOST_TEMPREG);
5350 emit_jcc((int)out-16); // -4
5351 emit_teq(d1,d2);
5352 emit_negmi(quotient,quotient);
5353 emit_test(d1,d1);
5354 emit_negmi(remainder,remainder);
5355 }
5356 if(opcode2[i]==0x1B) // DIVU
5357 {
5358 signed char d1=get_reg(i_regs->regmap,rs1[i]); // dividend
5359 signed char d2=get_reg(i_regs->regmap,rs2[i]); // divisor
5360 assert(d1>=0);
5361 assert(d2>=0);
5362 signed char quotient=get_reg(i_regs->regmap,LOREG);
5363 signed char remainder=get_reg(i_regs->regmap,HIREG);
5364 assert(quotient>=0);
5365 assert(remainder>=0);
44a80f6a 5366 emit_mov(d1,remainder);
5367 emit_movimm(0xffffffff,quotient); // div0 case
57871462 5368 emit_test(d2,d2);
44a80f6a 5369 emit_jeq((int)out+40); // Division by zero
665f33e1 5370#ifdef HAVE_ARMV5
57871462 5371 emit_clz(d2,HOST_TEMPREG);
5372 emit_movimm(1<<31,quotient);
5373 emit_shl(d2,HOST_TEMPREG,d2);
665f33e1 5374#else
5375 emit_movimm(0,HOST_TEMPREG);
82336ba3 5376 emit_addpl_imm(HOST_TEMPREG,1,HOST_TEMPREG);
5377 emit_lslpls_imm(d2,1,d2);
665f33e1 5378 emit_jns((int)out-2*4);
5379 emit_movimm(1<<31,quotient);
5380#endif
57871462 5381 emit_shr(quotient,HOST_TEMPREG,quotient);
5382 emit_cmp(remainder,d2);
5383 emit_subcs(remainder,d2,remainder);
5384 emit_adcs(quotient,quotient,quotient);
5385 emit_shrcc_imm(d2,1,d2);
5386 emit_jcc((int)out-16); // -4
5387 }
5388 }
5389 else // 64-bit
4600ba03 5390#ifndef FORCE32
57871462 5391 {
5392 if(opcode2[i]==0x1C) // DMULT
5393 {
5394 assert(opcode2[i]!=0x1C);
5395 signed char m1h=get_reg(i_regs->regmap,rs1[i]|64);
5396 signed char m1l=get_reg(i_regs->regmap,rs1[i]);
5397 signed char m2h=get_reg(i_regs->regmap,rs2[i]|64);
5398 signed char m2l=get_reg(i_regs->regmap,rs2[i]);
5399 assert(m1h>=0);
5400 assert(m2h>=0);
5401 assert(m1l>=0);
5402 assert(m2l>=0);
5403 emit_pushreg(m2h);
5404 emit_pushreg(m2l);
5405 emit_pushreg(m1h);
5406 emit_pushreg(m1l);
5407 emit_call((int)&mult64);
5408 emit_popreg(m1l);
5409 emit_popreg(m1h);
5410 emit_popreg(m2l);
5411 emit_popreg(m2h);
5412 signed char hih=get_reg(i_regs->regmap,HIREG|64);
5413 signed char hil=get_reg(i_regs->regmap,HIREG);
5414 if(hih>=0) emit_loadreg(HIREG|64,hih);
5415 if(hil>=0) emit_loadreg(HIREG,hil);
5416 signed char loh=get_reg(i_regs->regmap,LOREG|64);
5417 signed char lol=get_reg(i_regs->regmap,LOREG);
5418 if(loh>=0) emit_loadreg(LOREG|64,loh);
5419 if(lol>=0) emit_loadreg(LOREG,lol);
5420 }
5421 if(opcode2[i]==0x1D) // DMULTU
5422 {
5423 signed char m1h=get_reg(i_regs->regmap,rs1[i]|64);
5424 signed char m1l=get_reg(i_regs->regmap,rs1[i]);
5425 signed char m2h=get_reg(i_regs->regmap,rs2[i]|64);
5426 signed char m2l=get_reg(i_regs->regmap,rs2[i]);
5427 assert(m1h>=0);
5428 assert(m2h>=0);
5429 assert(m1l>=0);
5430 assert(m2l>=0);
4d646738 5431 save_regs(CALLER_SAVE_REGS);
57871462 5432 if(m1l!=0) emit_mov(m1l,0);
5433 if(m1h==0) emit_readword((int)&dynarec_local,1);
5434 else if(m1h>1) emit_mov(m1h,1);
5435 if(m2l<2) emit_readword((int)&dynarec_local+m2l*4,2);
5436 else if(m2l>2) emit_mov(m2l,2);
5437 if(m2h<3) emit_readword((int)&dynarec_local+m2h*4,3);
5438 else if(m2h>3) emit_mov(m2h,3);
5439 emit_call((int)&multu64);
4d646738 5440 restore_regs(CALLER_SAVE_REGS);
57871462 5441 signed char hih=get_reg(i_regs->regmap,HIREG|64);
5442 signed char hil=get_reg(i_regs->regmap,HIREG);
5443 signed char loh=get_reg(i_regs->regmap,LOREG|64);
5444 signed char lol=get_reg(i_regs->regmap,LOREG);
5445 /*signed char temp=get_reg(i_regs->regmap,-1);
5446 signed char rh=get_reg(i_regs->regmap,HIREG|64);
5447 signed char rl=get_reg(i_regs->regmap,HIREG);
5448 assert(m1h>=0);
5449 assert(m2h>=0);
5450 assert(m1l>=0);
5451 assert(m2l>=0);
5452 assert(temp>=0);
5453 //emit_mov(m1l,EAX);
5454 //emit_mul(m2l);
5455 emit_umull(rl,rh,m1l,m2l);
5456 emit_storereg(LOREG,rl);
5457 emit_mov(rh,temp);
5458 //emit_mov(m1h,EAX);
5459 //emit_mul(m2l);
5460 emit_umull(rl,rh,m1h,m2l);
5461 emit_adds(rl,temp,temp);
5462 emit_adcimm(rh,0,rh);
5463 emit_storereg(HIREG,rh);
5464 //emit_mov(m2h,EAX);
5465 //emit_mul(m1l);
5466 emit_umull(rl,rh,m1l,m2h);
5467 emit_adds(rl,temp,temp);
5468 emit_adcimm(rh,0,rh);
5469 emit_storereg(LOREG|64,temp);
5470 emit_mov(rh,temp);
5471 //emit_mov(m2h,EAX);
5472 //emit_mul(m1h);
5473 emit_umull(rl,rh,m1h,m2h);
5474 emit_adds(rl,temp,rl);
5475 emit_loadreg(HIREG,temp);
5476 emit_adcimm(rh,0,rh);
5477 emit_adds(rl,temp,rl);
5478 emit_adcimm(rh,0,rh);
5479 // DEBUG
5480 /*
5481 emit_pushreg(m2h);
5482 emit_pushreg(m2l);
5483 emit_pushreg(m1h);
5484 emit_pushreg(m1l);
5485 emit_call((int)&multu64);
5486 emit_popreg(m1l);
5487 emit_popreg(m1h);
5488 emit_popreg(m2l);
5489 emit_popreg(m2h);
5490 signed char hih=get_reg(i_regs->regmap,HIREG|64);
5491 signed char hil=get_reg(i_regs->regmap,HIREG);
5492 if(hih>=0) emit_loadreg(HIREG|64,hih); // DEBUG
5493 if(hil>=0) emit_loadreg(HIREG,hil); // DEBUG
5494 */
5495 // Shouldn't be necessary
5496 //char loh=get_reg(i_regs->regmap,LOREG|64);
5497 //char lol=get_reg(i_regs->regmap,LOREG);
5498 //if(loh>=0) emit_loadreg(LOREG|64,loh);
5499 //if(lol>=0) emit_loadreg(LOREG,lol);
5500 }
5501 if(opcode2[i]==0x1E) // DDIV
5502 {
5503 signed char d1h=get_reg(i_regs->regmap,rs1[i]|64);
5504 signed char d1l=get_reg(i_regs->regmap,rs1[i]);
5505 signed char d2h=get_reg(i_regs->regmap,rs2[i]|64);
5506 signed char d2l=get_reg(i_regs->regmap,rs2[i]);
5507 assert(d1h>=0);
5508 assert(d2h>=0);
5509 assert(d1l>=0);
5510 assert(d2l>=0);
4d646738 5511 save_regs(CALLER_SAVE_REGS);
57871462 5512 if(d1l!=0) emit_mov(d1l,0);
5513 if(d1h==0) emit_readword((int)&dynarec_local,1);
5514 else if(d1h>1) emit_mov(d1h,1);
5515 if(d2l<2) emit_readword((int)&dynarec_local+d2l*4,2);
5516 else if(d2l>2) emit_mov(d2l,2);
5517 if(d2h<3) emit_readword((int)&dynarec_local+d2h*4,3);
5518 else if(d2h>3) emit_mov(d2h,3);
5519 emit_call((int)&div64);
4d646738 5520 restore_regs(CALLER_SAVE_REGS);
57871462 5521 signed char hih=get_reg(i_regs->regmap,HIREG|64);
5522 signed char hil=get_reg(i_regs->regmap,HIREG);
5523 signed char loh=get_reg(i_regs->regmap,LOREG|64);
5524 signed char lol=get_reg(i_regs->regmap,LOREG);
5525 if(hih>=0) emit_loadreg(HIREG|64,hih);
5526 if(hil>=0) emit_loadreg(HIREG,hil);
5527 if(loh>=0) emit_loadreg(LOREG|64,loh);
5528 if(lol>=0) emit_loadreg(LOREG,lol);
5529 }
5530 if(opcode2[i]==0x1F) // DDIVU
5531 {
5532 //u_int hr,reglist=0;
5533 //for(hr=0;hr<HOST_REGS;hr++) {
5534 // if(i_regs->regmap[hr]>=0 && (i_regs->regmap[hr]&62)!=HIREG) reglist|=1<<hr;
5535 //}
5536 signed char d1h=get_reg(i_regs->regmap,rs1[i]|64);
5537 signed char d1l=get_reg(i_regs->regmap,rs1[i]);
5538 signed char d2h=get_reg(i_regs->regmap,rs2[i]|64);
5539 signed char d2l=get_reg(i_regs->regmap,rs2[i]);
5540 assert(d1h>=0);
5541 assert(d2h>=0);
5542 assert(d1l>=0);
5543 assert(d2l>=0);
4d646738 5544 save_regs(CALLER_SAVE_REGS);
57871462 5545 if(d1l!=0) emit_mov(d1l,0);
5546 if(d1h==0) emit_readword((int)&dynarec_local,1);
5547 else if(d1h>1) emit_mov(d1h,1);
5548 if(d2l<2) emit_readword((int)&dynarec_local+d2l*4,2);
5549 else if(d2l>2) emit_mov(d2l,2);
5550 if(d2h<3) emit_readword((int)&dynarec_local+d2h*4,3);
5551 else if(d2h>3) emit_mov(d2h,3);
5552 emit_call((int)&divu64);
4d646738 5553 restore_regs(CALLER_SAVE_REGS);
57871462 5554 signed char hih=get_reg(i_regs->regmap,HIREG|64);
5555 signed char hil=get_reg(i_regs->regmap,HIREG);
5556 signed char loh=get_reg(i_regs->regmap,LOREG|64);
5557 signed char lol=get_reg(i_regs->regmap,LOREG);
5558 if(hih>=0) emit_loadreg(HIREG|64,hih);
5559 if(hil>=0) emit_loadreg(HIREG,hil);
5560 if(loh>=0) emit_loadreg(LOREG|64,loh);
5561 if(lol>=0) emit_loadreg(LOREG,lol);
5562 }
5563 }
4600ba03 5564#else
5565 assert(0);
5566#endif
57871462 5567 }
5568 else
5569 {
5570 // Multiply by zero is zero.
5571 // MIPS does not have a divide by zero exception.
5572 // The result is undefined, we return zero.
5573 signed char hr=get_reg(i_regs->regmap,HIREG);
5574 signed char lr=get_reg(i_regs->regmap,LOREG);
5575 if(hr>=0) emit_zeroreg(hr);
5576 if(lr>=0) emit_zeroreg(lr);
5577 }
5578}
5579#define multdiv_assemble multdiv_assemble_arm
5580
5581void do_preload_rhash(int r) {
5582 // Don't need this for ARM. On x86, this puts the value 0xf8 into the
5583 // register. On ARM the hash can be done with a single instruction (below)
5584}
5585
5586void do_preload_rhtbl(int ht) {
5587 emit_addimm(FP,(int)&mini_ht-(int)&dynarec_local,ht);
5588}
5589
5590void do_rhash(int rs,int rh) {
5591 emit_andimm(rs,0xf8,rh);
5592}
5593
5594void do_miniht_load(int ht,int rh) {
5595 assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
5596 output_w32(0xe7b00000|rd_rn_rm(rh,ht,rh));
5597}
5598
5599void do_miniht_jump(int rs,int rh,int ht) {
5600 emit_cmp(rh,rs);
5601 emit_ldreq_indexed(ht,4,15);
5602 #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK
5603 emit_mov(rs,7);
5604 emit_jmp(jump_vaddr_reg[7]);
5605 #else
5606 emit_jmp(jump_vaddr_reg[rs]);
5607 #endif
5608}
5609
5610void do_miniht_insert(u_int return_address,int rt,int temp) {
665f33e1 5611 #ifndef HAVE_ARMV7
57871462 5612 emit_movimm(return_address,rt); // PC into link register
5613 add_to_linker((int)out,return_address,1);
5614 emit_pcreladdr(temp);
5615 emit_writeword(rt,(int)&mini_ht[(return_address&0xFF)>>3][0]);
5616 emit_writeword(temp,(int)&mini_ht[(return_address&0xFF)>>3][1]);
5617 #else
5618 emit_movw(return_address&0x0000FFFF,rt);
5619 add_to_linker((int)out,return_address,1);
5620 emit_pcreladdr(temp);
5621 emit_writeword(temp,(int)&mini_ht[(return_address&0xFF)>>3][1]);
5622 emit_movt(return_address&0xFFFF0000,rt);
5623 emit_writeword(rt,(int)&mini_ht[(return_address&0xFF)>>3][0]);
5624 #endif
5625}
5626
5627// Sign-extend to 64 bits and write out upper half of a register
5628// This is useful where we have a 32-bit value in a register, and want to
5629// keep it in a 32-bit register, but can't guarantee that it won't be read
5630// as a 64-bit value later.
5631void wb_sx(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32_pre,uint64_t is32,uint64_t u,uint64_t uu)
5632{
24385cae 5633#ifndef FORCE32
57871462 5634 if(is32_pre==is32) return;
5635 int hr,reg;
5636 for(hr=0;hr<HOST_REGS;hr++) {
5637 if(hr!=EXCLUDE_REG) {
5638 //if(pre[hr]==entry[hr]) {
5639 if((reg=pre[hr])>=0) {
5640 if((dirty>>hr)&1) {
5641 if( ((is32_pre&~is32&~uu)>>reg)&1 ) {
5642 emit_sarimm(hr,31,HOST_TEMPREG);
5643 emit_storereg(reg|64,HOST_TEMPREG);
5644 }
5645 }
5646 }
5647 //}
5648 }
5649 }
24385cae 5650#endif
57871462 5651}
5652
5653void wb_valid(signed char pre[],signed char entry[],u_int dirty_pre,u_int dirty,uint64_t is32_pre,uint64_t u,uint64_t uu)
5654{
5655 //if(dirty_pre==dirty) return;
5656 int hr,reg,new_hr;
5657 for(hr=0;hr<HOST_REGS;hr++) {
5658 if(hr!=EXCLUDE_REG) {
5659 reg=pre[hr];
5660 if(((~u)>>(reg&63))&1) {
f776eb14 5661 if(reg>0) {
57871462 5662 if(((dirty_pre&~dirty)>>hr)&1) {
5663 if(reg>0&&reg<34) {
5664 emit_storereg(reg,hr);
5665 if( ((is32_pre&~uu)>>reg)&1 ) {
5666 emit_sarimm(hr,31,HOST_TEMPREG);
5667 emit_storereg(reg|64,HOST_TEMPREG);
5668 }
5669 }
5670 else if(reg>=64) {
5671 emit_storereg(reg,hr);
5672 }
5673 }
5674 }
57871462 5675 }
5676 }
5677 }
5678}
5679
5680
5681/* using strd could possibly help but you'd have to allocate registers in pairs
5682void wb_invalidate_arm(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32,uint64_t u,uint64_t uu)
5683{
5684 int hr;
5685 int wrote=-1;
5686 for(hr=HOST_REGS-1;hr>=0;hr--) {
5687 if(hr!=EXCLUDE_REG) {
5688 if(pre[hr]!=entry[hr]) {
5689 if(pre[hr]>=0) {
5690 if((dirty>>hr)&1) {
5691 if(get_reg(entry,pre[hr])<0) {
5692 if(pre[hr]<64) {
5693 if(!((u>>pre[hr])&1)) {
5694 if(hr<10&&(~hr&1)&&(pre[hr+1]<0||wrote==hr+1)) {
5695 if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) {
5696 emit_sarimm(hr,31,hr+1);
5697 emit_strdreg(pre[hr],hr);
5698 }
5699 else
5700 emit_storereg(pre[hr],hr);
5701 }else{
5702 emit_storereg(pre[hr],hr);
5703 if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) {
5704 emit_sarimm(hr,31,hr);
5705 emit_storereg(pre[hr]|64,hr);
5706 }
5707 }
5708 }
5709 }else{
5710 if(!((uu>>(pre[hr]&63))&1) && !((is32>>(pre[hr]&63))&1)) {
5711 emit_storereg(pre[hr],hr);
5712 }
5713 }
5714 wrote=hr;
5715 }
5716 }
5717 }
5718 }
5719 }
5720 }
5721 for(hr=0;hr<HOST_REGS;hr++) {
5722 if(hr!=EXCLUDE_REG) {
5723 if(pre[hr]!=entry[hr]) {
5724 if(pre[hr]>=0) {
5725 int nr;
5726 if((nr=get_reg(entry,pre[hr]))>=0) {
5727 emit_mov(hr,nr);
5728 }
5729 }
5730 }
5731 }
5732 }
5733}
5734#define wb_invalidate wb_invalidate_arm
5735*/
5736
dd3a91a1 5737// Clearing the cache is rather slow on ARM Linux, so mark the areas
5738// that need to be cleared, and then only clear these areas once.
5739void do_clear_cache()
5740{
5741 int i,j;
5742 for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
5743 {
5744 u_int bitmap=needs_clear_cache[i];
5745 if(bitmap) {
5746 u_int start,end;
5747 for(j=0;j<32;j++)
5748 {
5749 if(bitmap&(1<<j)) {
bdeade46 5750 start=(u_int)BASE_ADDR+i*131072+j*4096;
dd3a91a1 5751 end=start+4095;
5752 j++;
5753 while(j<32) {
5754 if(bitmap&(1<<j)) {
5755 end+=4096;
5756 j++;
5757 }else{
5758 __clear_cache((void *)start,(void *)end);
5759 break;
5760 }
5761 }
5762 }
5763 }
5764 needs_clear_cache[i]=0;
5765 }
5766 }
5767}
5768
57871462 5769// CPU-architecture-specific initialization
5770void arch_init() {
3d624f89 5771#ifndef DISABLE_COP1
57871462 5772 rounding_modes[0]=0x0<<22; // round
5773 rounding_modes[1]=0x3<<22; // trunc
5774 rounding_modes[2]=0x1<<22; // ceil
5775 rounding_modes[3]=0x2<<22; // floor
3d624f89 5776#endif
57871462 5777}
b9b61529 5778
5779// vim:shiftwidth=2:expandtab