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