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