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