df5b5aaa2d0409751429c6b0bfe1e30391801e55
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / assem_arm64.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus/PCSX - assem_arm64.c                                      *
3  *   Copyright (C) 2009-2011 Ari64                                         *
4  *   Copyright (C) 2010-2021 notaz                                         *
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
22 #include "arm_features.h"
23
24 #if   defined(BASE_ADDR_FIXED)
25 #elif defined(BASE_ADDR_DYNAMIC)
26 u_char *translation_cache;
27 #else
28 u_char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
29 #endif
30
31 #define CALLER_SAVE_REGS 0x0007ffff
32
33 #define unused __attribute__((unused))
34
35 static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
36
37 //void indirect_jump_indexed();
38 //void indirect_jump();
39 void do_interrupt();
40 //void jump_vaddr_r0();
41
42 void * const jump_vaddr_reg[32];
43
44 /* Linker */
45
46 static void set_jump_target(void *addr, void *target_)
47 {
48   assert(0);
49 }
50
51 // from a pointer to external jump stub (which was produced by emit_extjump2)
52 // find where the jumping insn is
53 static void *find_extjump_insn(void *stub)
54 {
55   assert(0);
56   return NULL;
57 }
58
59 // find where external branch is liked to using addr of it's stub:
60 // get address that insn one after stub loads (dyna_linker arg1),
61 // treat it as a pointer to branch insn,
62 // return addr where that branch jumps to
63 static void *get_pointer(void *stub)
64 {
65   //printf("get_pointer(%x)\n",(int)stub);
66   assert(0);
67   return NULL;
68 }
69
70 // Find the "clean" entry point from a "dirty" entry point
71 // by skipping past the call to verify_code
72 static void *get_clean_addr(void *addr)
73 {
74   assert(0);
75   return NULL;
76 }
77
78 static int verify_dirty(u_int *ptr)
79 {
80   assert(0);
81   return 0;
82 }
83
84 // This doesn't necessarily find all clean entry points, just
85 // guarantees that it's not dirty
86 static int isclean(void *addr)
87 {
88   assert(0);
89   return 0;
90 }
91
92 // get source that block at addr was compiled from (host pointers)
93 static void get_bounds(void *addr, u_char **start, u_char **end)
94 {
95   assert(0);
96 }
97
98 // Allocate a specific ARM register.
99 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
100 {
101   int n;
102   int dirty=0;
103
104   // see if it's already allocated (and dealloc it)
105   for(n=0;n<HOST_REGS;n++)
106   {
107     if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
108       dirty=(cur->dirty>>n)&1;
109       cur->regmap[n]=-1;
110     }
111   }
112
113   cur->regmap[hr]=reg;
114   cur->dirty&=~(1<<hr);
115   cur->dirty|=dirty<<hr;
116   cur->isconst&=~(1<<hr);
117 }
118
119 // Alloc cycle count into dedicated register
120 static void alloc_cc(struct regstat *cur,int i)
121 {
122   alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
123 }
124
125 /* Special alloc */
126
127
128 /* Assembler */
129
130 static unused const char *regname[32] = {
131   "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6", "r7",
132   "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15"
133  "ip0", "ip1", "r18", "r19", "r20", "r21", "r22", "r23"
134  "r24", "r25", "r26", "r27", "r28",  "fp",  "lr",  "sp"
135 };
136
137 static void output_w32(u_int word)
138 {
139   *((u_int *)out) = word;
140   out += 4;
141 }
142
143 static u_int rm_rd(u_int rm, u_int rd)
144 {
145   assert(rm < 31);
146   assert(rd < 31);
147   return (rm << 16) | rd;
148 }
149
150 static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
151 {
152   assert(rm < 31);
153   assert(rn < 31);
154   assert(rd < 31);
155   return (rm << 16) | (rn << 5) | rd;
156 }
157
158 static u_int rm_imm6_rn_rd(u_int rm, u_int imm6, u_int rn, u_int rd)
159 {
160   assert(imm6 <= 63);
161   return rm_rn_rd(rm, rn, rd) | (imm6 << 10);
162 }
163
164 static u_int imm16_rd(u_int imm16, u_int rd)
165 {
166   assert(imm16 < 0x10000);
167   assert(rd < 31);
168   return (imm16 << 5) | rd;
169 }
170
171 static u_int imm12_rn_rd(u_int imm12, u_int rn, u_int rd)
172 {
173   assert(imm12 < 0x1000);
174   assert(rn < 31);
175   assert(rd < 31);
176   return (imm12 << 10) | (rn << 5) | rd;
177 }
178
179 #pragma GCC diagnostic ignored "-Wunused-function"
180 static u_int genjmp(u_char *addr)
181 {
182   intptr_t offset = addr - out;
183   if (offset < -134217728 || offset > 134217727) {
184     if ((uintptr_t)addr > 2) {
185       SysPrintf("%s: out of range: %08x\n", __func__, offset);
186       exit(1);
187     }
188     return 0;
189   }
190   return ((u_int)offset >> 2) & 0x01ffffff;
191 }
192
193 static u_int genjmpcc(u_char *addr)
194 {
195   intptr_t offset = addr - out;
196   if (offset < -1048576 || offset > 1048572) {
197     if ((uintptr_t)addr > 2) {
198       SysPrintf("%s: out of range: %08x\n", __func__, offset);
199       exit(1);
200     }
201     return 0;
202   }
203   return ((u_int)offset >> 2) & 0xfffff;
204 }
205
206 static void emit_mov(u_int rs, u_int rt)
207 {
208   assem_debug("mov %s,%s\n", regname[rt], regname[rs]);
209   output_w32(0x2a0003e0 | rm_rd(rs, rt));
210 }
211
212 static void emit_movs(u_int rs, u_int rt)
213 {
214   assem_debug("movs %s,%s\n", regname[rt], regname[rs]);
215   output_w32(0x31000000 | imm12_rn_rd(0, rs, rt));
216 }
217
218 static void emit_add(u_int rs1, u_int rs2, u_int rt)
219 {
220   assem_debug("add %s, %s, %s\n", regname[rt], regname[rs1], regname[rs2]);
221   output_w32(0x0b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
222 }
223
224 static void emit_sbc(u_int rs1,u_int rs2,u_int rt)
225 {
226   assem_debug("sbc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
227   assert(0);
228 }
229
230 static void emit_neg(u_int rs, u_int rt)
231 {
232   assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
233   assert(0);
234 }
235
236 static void emit_negs(u_int rs, u_int rt)
237 {
238   assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]);
239   assert(0);
240 }
241
242 static void emit_sub(u_int rs1, u_int rs2, u_int rt)
243 {
244   assem_debug("sub %s, %s, %s\n", regname[rt], regname[rs1], regname[rs2]);
245   output_w32(0x4b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
246 }
247
248 static void emit_subs(u_int rs1,u_int rs2,u_int rt)
249 {
250   assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
251   assert(0);
252 }
253
254 static void emit_zeroreg(u_int rt)
255 {
256   assem_debug("mov %s,#0\n",regname[rt]);
257   assert(0);
258 }
259
260 static void emit_movimm(u_int imm, u_int rt)
261 {
262   assem_debug("mov %s,#%#x\n", regname[rt], imm);
263   if      ((imm & 0xffff0000) == 0)
264     output_w32(0x52800000 | imm16_rd(imm, rt));
265   else if ((imm & 0xffff0000) == 0xffff0000)
266     assert(0);
267   else {
268     output_w32(0x52800000 | imm16_rd(imm & 0xffff, rt));
269     output_w32(0x72a00000 | imm16_rd(imm >> 16, rt));
270   }
271 }
272
273 static void emit_readword(void *addr, u_int rt)
274 {
275   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
276   if (!(offset & 3) && offset <= 16380) {
277     assem_debug("ldr %s,[x%d+%#lx]\n", regname[rt], FP, offset);
278     output_w32(0xb9400000 | imm12_rn_rd(offset >> 2, FP, rt));
279   }
280   else
281     assert(0);
282 }
283
284 static void emit_loadreg(u_int r, u_int hr)
285 {
286   assert(r < 64);
287   if (r == 0)
288     emit_zeroreg(hr);
289   else {
290     void *addr = &reg[r];
291     switch (r) {
292     case HIREG: addr = &hi; break;
293     case LOREG: addr = &lo; break;
294     case CCREG: addr = &cycle_count; break;
295     case CSREG: addr = &Status; break;
296     case INVCP: addr = &invc_ptr; break;
297     default: assert(r < 32); break;
298     }
299     emit_readword(addr, hr);
300   }
301 }
302
303 static void emit_writeword(u_int rt, void *addr)
304 {
305   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
306   if (!(offset & 3) && offset <= 16380) {
307     assem_debug("str %s,[x%d+%#lx]\n", regname[rt], FP, offset);
308     output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, FP, rt));
309   }
310   else
311     assert(0);
312 }
313
314 static void emit_storereg(u_int r, u_int hr)
315 {
316   assert(r < 64);
317   void *addr = &reg[r];
318   switch (r) {
319   case HIREG: addr = &hi; break;
320   case LOREG: addr = &lo; break;
321   case CCREG: addr = &cycle_count; break;
322   default: assert(r < 32); break;
323   }
324   emit_writeword(hr, addr);
325 }
326
327 static void emit_test(u_int rs, u_int rt)
328 {
329   assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
330   assert(0);
331 }
332
333 static void emit_testimm(u_int rs,int imm)
334 {
335   assem_debug("tst %s,#%#x\n", regname[rs], imm);
336   assert(0);
337 }
338
339 static void emit_testeqimm(u_int rs,int imm)
340 {
341   assem_debug("tsteq %s,$%d\n",regname[rs],imm);
342   assert(0);
343 }
344
345 static void emit_not(u_int rs,u_int rt)
346 {
347   assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
348   assert(0);
349 }
350
351 static void emit_mvnmi(u_int rs,u_int rt)
352 {
353   assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
354   assert(0);
355 }
356
357 static void emit_and(u_int rs1,u_int rs2,u_int rt)
358 {
359   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
360   assert(0);
361 }
362
363 static void emit_or(u_int rs1,u_int rs2,u_int rt)
364 {
365   assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
366   assert(0);
367 }
368
369 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
370 {
371   assert(rs < 31);
372   assert(rt < 31);
373   assert(imm < 32);
374   assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
375   assert(0);
376 }
377
378 static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
379 {
380   assert(rs < 31);
381   assert(rt < 31);
382   assert(imm < 32);
383   assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
384   assert(0);
385 }
386
387 static void emit_or_and_set_flags(u_int rs1,u_int rs2,u_int rt)
388 {
389   assem_debug("orrs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
390   assert(0);
391 }
392
393 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
394 {
395   assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
396   assert(0);
397 }
398
399 static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
400 {
401   if (imm < 4096) {
402     assem_debug("add %s,%s,%#lx\n", regname[rt], regname[rs], imm);
403     output_w32(0x11000000 | imm12_rn_rd(imm, rs, rt));
404   }
405   else if (-imm < 4096) {
406     assem_debug("sub %s,%s,%#lx\n", regname[rt], regname[rs], imm);
407     output_w32(0x51000000 | imm12_rn_rd(imm, rs, rt));
408   }
409   else
410     assert(0);
411 }
412
413 static void emit_addimm_and_set_flags(int imm, u_int rt)
414 {
415   assert(0);
416 }
417
418 static void emit_addimm_no_flags(u_int imm,u_int rt)
419 {
420   emit_addimm(rt,imm,rt);
421 }
422
423 static void emit_adcimm(u_int rs,int imm,u_int rt)
424 {
425   assem_debug("adc %s,%s,#%#x\n",regname[rt],regname[rs],imm);
426   assert(0);
427 }
428
429 static void emit_rscimm(u_int rs,int imm,u_int rt)
430 {
431   assem_debug("rsc %s,%s,#%#x\n",regname[rt],regname[rs],imm);
432   assert(0);
433 }
434
435 static void emit_addimm64_32(u_int rsh,u_int rsl,int imm,u_int rth,u_int rtl)
436 {
437   assert(0);
438 }
439
440 static void emit_andimm(u_int rs,int imm,u_int rt)
441 {
442   assert(0);
443 }
444
445 static void emit_orimm(u_int rs,int imm,u_int rt)
446 {
447   assert(0);
448 }
449
450 static void emit_xorimm(u_int rs,int imm,u_int rt)
451 {
452   assert(0);
453 }
454
455 static void emit_shlimm(u_int rs,u_int imm,u_int rt)
456 {
457   assert(imm>0);
458   assert(imm<32);
459   assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
460   assert(0);
461 }
462
463 static void emit_lsls_imm(u_int rs,int imm,u_int rt)
464 {
465   assert(imm>0);
466   assert(imm<32);
467   assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
468   assert(0);
469 }
470
471 static unused void emit_lslpls_imm(u_int rs,int imm,u_int rt)
472 {
473   assert(imm>0);
474   assert(imm<32);
475   assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
476   assert(0);
477 }
478
479 static void emit_shrimm(u_int rs,u_int imm,u_int rt)
480 {
481   assert(imm>0);
482   assert(imm<32);
483   assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
484   assert(0);
485 }
486
487 static void emit_sarimm(u_int rs,u_int imm,u_int rt)
488 {
489   assert(imm>0);
490   assert(imm<32);
491   assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
492   assert(0);
493 }
494
495 static void emit_rorimm(u_int rs,u_int imm,u_int rt)
496 {
497   assert(imm>0);
498   assert(imm<32);
499   assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
500   assert(0);
501 }
502
503 static void emit_signextend16(u_int rs, u_int rt)
504 {
505   assem_debug("sxth %s,%s\n", regname[rt], regname[rs]);
506   assert(0);
507 }
508
509 static void emit_shl(u_int rs,u_int shift,u_int rt)
510 {
511   assert(rs < 31);
512   assert(rt < 31);
513   assert(shift < 16);
514   assert(0);
515 }
516
517 static void emit_shr(u_int rs,u_int shift,u_int rt)
518 {
519   assert(rs < 31);
520   assert(rt < 31);
521   assert(shift<16);
522   assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
523   assert(0);
524 }
525
526 static void emit_sar(u_int rs,u_int shift,u_int rt)
527 {
528   assert(rs < 31);
529   assert(rt < 31);
530   assert(shift<16);
531   assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
532   assert(0);
533 }
534
535 static void emit_orrshl(u_int rs,u_int shift,u_int rt)
536 {
537   assert(rs < 31);
538   assert(rt < 31);
539   assert(shift<16);
540   assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
541   assert(0);
542 }
543
544 static void emit_orrshr(u_int rs,u_int shift,u_int rt)
545 {
546   assert(rs < 31);
547   assert(rt < 31);
548   assert(shift<16);
549   assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
550   assert(0);
551 }
552
553 static void emit_cmpimm(u_int rs,int imm)
554 {
555   assert(0);
556 }
557
558 static void emit_cmovne_imm(int imm,u_int rt)
559 {
560   assem_debug("movne %s,#%#x\n",regname[rt],imm);
561   assert(0);
562 }
563
564 static void emit_cmovl_imm(int imm,u_int rt)
565 {
566   assem_debug("movlt %s,#%#x\n",regname[rt],imm);
567   assert(0);
568 }
569
570 static void emit_cmovb_imm(int imm,u_int rt)
571 {
572   assem_debug("movcc %s,#%#x\n",regname[rt],imm);
573   assert(0);
574 }
575
576 static void emit_cmovs_imm(int imm,u_int rt)
577 {
578   assem_debug("movmi %s,#%#x\n",regname[rt],imm);
579   assert(0);
580 }
581
582 static void emit_cmovne_reg(u_int rs,u_int rt)
583 {
584   assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
585   assert(0);
586 }
587
588 static void emit_cmovl_reg(u_int rs,u_int rt)
589 {
590   assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
591   assert(0);
592 }
593
594 static void emit_cmovs_reg(u_int rs,u_int rt)
595 {
596   assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
597   assert(0);
598 }
599
600 static void emit_slti32(u_int rs,int imm,u_int rt)
601 {
602   if(rs!=rt) emit_zeroreg(rt);
603   emit_cmpimm(rs,imm);
604   if(rs==rt) emit_movimm(0,rt);
605   emit_cmovl_imm(1,rt);
606 }
607
608 static void emit_sltiu32(u_int rs,int imm,u_int rt)
609 {
610   if(rs!=rt) emit_zeroreg(rt);
611   emit_cmpimm(rs,imm);
612   if(rs==rt) emit_movimm(0,rt);
613   emit_cmovb_imm(1,rt);
614 }
615
616 static void emit_cmp(u_int rs,u_int rt)
617 {
618   assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
619   assert(0);
620 }
621
622 static void emit_set_gz32(u_int rs, u_int rt)
623 {
624   //assem_debug("set_gz32\n");
625   emit_cmpimm(rs,1);
626   emit_movimm(1,rt);
627   emit_cmovl_imm(0,rt);
628 }
629
630 static void emit_set_nz32(u_int rs, u_int rt)
631 {
632   //assem_debug("set_nz32\n");
633   assert(0);
634 }
635
636 static void emit_set_if_less32(u_int rs1, u_int rs2, u_int rt)
637 {
638   //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
639   if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
640   emit_cmp(rs1,rs2);
641   if(rs1==rt||rs2==rt) emit_movimm(0,rt);
642   emit_cmovl_imm(1,rt);
643 }
644
645 static void emit_set_if_carry32(u_int rs1, u_int rs2, u_int rt)
646 {
647   //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
648   if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
649   emit_cmp(rs1,rs2);
650   if(rs1==rt||rs2==rt) emit_movimm(0,rt);
651   emit_cmovb_imm(1,rt);
652 }
653
654 static void emit_call(const void *a_)
655 {
656   intptr_t diff = (u_char *)a_ - out;
657   assem_debug("bl %p (%p+%lx)%s\n", a_, out, diff, func_name(a));
658   assert(!(diff & 3));
659   if (-134217728 <= diff && diff <= 134217727)
660     output_w32(0x94000000 | ((diff >> 2) & 0x03ffffff));
661   else
662     assert(0);
663 }
664
665 #pragma GCC diagnostic ignored "-Wunused-variable"
666 static void emit_jmp(const void *a_)
667 {
668   uintptr_t a = (uintptr_t)a_;
669   assem_debug("b %p (%p+%lx)%s\n", a_, out, (u_char *)a_ - out, func_name(a));
670   assert(0);
671 }
672
673 static void emit_jne(const void *a_)
674 {
675   uintptr_t a = (uintptr_t)a_;
676   assem_debug("bne %p\n", a_);
677   assert(0);
678 }
679
680 static void emit_jeq(int a)
681 {
682   assem_debug("beq %x\n",a);
683   assert(0);
684 }
685
686 static void emit_js(int a)
687 {
688   assem_debug("bmi %x\n",a);
689   assert(0);
690 }
691
692 static void emit_jns(int a)
693 {
694   assem_debug("bpl %x\n",a);
695   assert(0);
696 }
697
698 static void emit_jl(int a)
699 {
700   assem_debug("blt %x\n",a);
701   assert(0);
702 }
703
704 static void emit_jge(int a)
705 {
706   assem_debug("bge %x\n",a);
707   assert(0);
708 }
709
710 static void emit_jno(int a)
711 {
712   assem_debug("bvc %x\n",a);
713   assert(0);
714 }
715
716 static void emit_jc(int a)
717 {
718   assem_debug("bcs %x\n",a);
719   assert(0);
720 }
721
722 static void emit_jcc(void *a_)
723 {
724   uintptr_t a = (uintptr_t)a_;
725   assem_debug("bcc %p\n", a_);
726   assert(0);
727 }
728
729 static void emit_callreg(u_int r)
730 {
731   assert(r < 31);
732   assem_debug("blx %s\n", regname[r]);
733   assert(0);
734 }
735
736 static void emit_jmpreg(u_int r)
737 {
738   assem_debug("mov pc,%s\n",regname[r]);
739   assert(0);
740 }
741
742 static void emit_retreg(u_int r)
743 {
744   assem_debug("ret %s\n", r == LR ? "" : regname[r]);
745   output_w32(0xd65f0000 | rm_rn_rd(0, r, 0));
746 }
747
748 static void emit_ret(void)
749 {
750   emit_retreg(LR);
751 }
752
753 static void emit_readword_indexed(int offset, u_int rs, u_int rt)
754 {
755   assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
756   assert(0);
757 }
758
759 static void emit_movsbl_indexed(int offset, u_int rs, u_int rt)
760 {
761   assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
762   assert(0);
763 }
764
765 static void emit_movswl_indexed(int offset, u_int rs, u_int rt)
766 {
767   assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
768   assert(0);
769 }
770
771 static void emit_movzbl_indexed(int offset, u_int rs, u_int rt)
772 {
773   assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
774   assert(0);
775 }
776
777 static void emit_movzwl_indexed(int offset, u_int rs, u_int rt)
778 {
779   assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
780   assert(0);
781 }
782
783 static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
784 {
785   assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
786   if (!(offset & 3) && offset <= 16380)
787     output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt));
788   else
789     assert(0);
790 }
791
792 static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
793 {
794   assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
795   if (!(offset & 1) && offset <= 8190)
796     output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt));
797   else
798     assert(0);
799 }
800
801 static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
802 {
803   assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
804   if ((u_int)offset < 4096)
805     output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt));
806   else
807     assert(0);
808 }
809
810 static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
811 {
812   assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
813   assert(rs1<16);
814   assert(rs2<16);
815   assert(hi<16);
816   assert(lo<16);
817   assert(0);
818 }
819
820 static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
821 {
822   assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
823   assert(rs1<16);
824   assert(rs2<16);
825   assert(hi<16);
826   assert(lo<16);
827   assert(0);
828 }
829
830 static void emit_clz(u_int rs,u_int rt)
831 {
832   assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
833   assert(0);
834 }
835
836 // Load 2 immediates optimizing for small code size
837 static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
838 {
839   assert(0);
840 }
841
842 // Conditionally select one of two immediates, optimizing for small code size
843 // This will only be called if HAVE_CMOV_IMM is defined
844 static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
845 {
846   assert(0);
847 }
848
849 // special case for checking invalid_code
850 static void emit_cmpmem_indexedsr12_reg(int base,u_int r,int imm)
851 {
852   assert(imm<128&&imm>=0);
853   assert(r>=0&&r<16);
854   assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
855   assert(0);
856 }
857
858 // Used to preload hash table entries
859 static unused void emit_prefetchreg(u_int r)
860 {
861   assem_debug("pld %s\n",regname[r]);
862   assert(0);
863 }
864
865 // Special case for mini_ht
866 static void emit_ldreq_indexed(u_int rs, u_int offset, u_int rt)
867 {
868   assert(offset<4096);
869   assem_debug("ldreq %s,[%s, #%#x]\n",regname[rt],regname[rs],offset);
870   assert(0);
871 }
872
873 static void emit_orrne_imm(u_int rs,int imm,u_int rt)
874 {
875   assem_debug("orrne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
876   assert(0);
877 }
878
879 static void emit_andne_imm(u_int rs,int imm,u_int rt)
880 {
881   assem_debug("andne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
882   assert(0);
883 }
884
885 static unused void emit_addpl_imm(u_int rs,int imm,u_int rt)
886 {
887   assem_debug("addpl %s,%s,#%#x\n",regname[rt],regname[rs],imm);
888   assert(0);
889 }
890
891 static void emit_ldst(int is_st, int is64, u_int rt, u_int rn, u_int ofs)
892 {
893   u_int op = 0xb9000000;
894   const char *ldst = is_st ? "st" : "ld";
895   char rp = is64 ? 'x' : 'w';
896   assem_debug("%sr %c%d,[x%d,#%#x]\n", ldst, rp, rt, rn, ofs);
897   is64 = is64 ? 1 : 0;
898   assert((ofs & ((1 << (2+is64)) - 1)) == 0);
899   ofs = (ofs >> (2+is64));
900   assert(ofs <= 0xfff);
901   if (!is_st) op |= 0x00400000;
902   if (is64)   op |= 0x40000000;
903   output_w32(op | (ofs << 15) | imm12_rn_rd(ofs, rn, rt));
904 }
905
906 static void emit_ldstp(int is_st, int is64, u_int rt1, u_int rt2, u_int rn, int ofs)
907 {
908   u_int op = 0x29000000;
909   const char *ldst = is_st ? "st" : "ld";
910   char rp = is64 ? 'x' : 'w';
911   assem_debug("%sp %c%d,%c%d,[x%d,#%#x]\n", ldst, rp, rt1, rp, rt2, rn, ofs);
912   is64 = is64 ? 1 : 0;
913   assert((ofs & ((1 << (2+is64)) - 1)) == 0);
914   ofs = (ofs >> (2+is64));
915   assert(-64 <= ofs && ofs <= 63);
916   ofs &= 0x7f;
917   if (!is_st) op |= 0x00400000;
918   if (is64)   op |= 0x80000000;
919   output_w32(op | (ofs << 15) | rm_rn_rd(rt2, rn, rt1));
920 }
921
922 static void save_load_regs_all(int is_store, u_int reglist)
923 {
924   int ofs = 0, c = 0;
925   u_int r, pair[2];
926   for (r = 0; reglist; r++, reglist >>= 1) {
927     if (reglist & 1)
928       pair[c++] = r;
929     if (c == 2) {
930       emit_ldstp(is_store, 1, pair[0], pair[1], SP, SSP_CALLEE_REGS + ofs);
931       ofs += 8 * 2;
932       c = 0;
933     }
934   }
935   if (c) {
936     emit_ldst(is_store, 1, pair[0], SP, SSP_CALLEE_REGS + ofs);
937     ofs += 8;
938   }
939   assert(ofs <= SSP_CALLER_REGS);
940 }
941
942 // Save registers before function call
943 static void save_regs(u_int reglist)
944 {
945   reglist &= CALLER_SAVE_REGS; // only save the caller-save registers
946   save_load_regs_all(1, reglist);
947 }
948
949 // Restore registers after function call
950 static void restore_regs(u_int reglist)
951 {
952   reglist &= CALLER_SAVE_REGS;
953   save_load_regs_all(0, reglist);
954 }
955
956 /* Stubs/epilogue */
957
958 static void literal_pool(int n)
959 {
960   (void)literals;
961 }
962
963 static void literal_pool_jumpover(int n)
964 {
965 }
966
967 static void emit_extjump2(u_char *addr, int target, void *linker)
968 {
969   assert(0);
970 }
971
972 static void emit_extjump(void *addr, int target)
973 {
974   emit_extjump2(addr, target, dyna_linker);
975 }
976
977 static void emit_extjump_ds(void *addr, int target)
978 {
979   emit_extjump2(addr, target, dyna_linker_ds);
980 }
981
982 // put rt_val into rt, potentially making use of rs with value rs_val
983 static void emit_movimm_from(u_int rs_val, u_int rs, uintptr_t rt_val, u_int rt)
984 {
985   intptr_t diff = rt_val - rs_val;
986   if (-4096 < diff && diff < 4096)
987     emit_addimm(rs, diff, rt);
988   else
989     // TODO: for inline_writestub, etc
990     assert(0);
991 }
992
993 // return 1 if above function can do it's job cheaply
994 static int is_similar_value(u_int v1, u_int v2)
995 {
996   int diff = v1 - v2;
997   return -4096 < diff && diff < 4096;
998 }
999
1000 //#include "pcsxmem.h"
1001 //#include "pcsxmem_inline.c"
1002
1003 static void do_readstub(int n)
1004 {
1005   assem_debug("do_readstub %x\n",start+stubs[n].a*4);
1006   assert(0);
1007 }
1008
1009 static void inline_readstub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1010 {
1011   assert(0);
1012 }
1013
1014 static void do_writestub(int n)
1015 {
1016   assem_debug("do_writestub %x\n",start+stubs[n].a*4);
1017   assert(0);
1018 }
1019
1020 static void inline_writestub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1021 {
1022   int rs = get_reg(regmap,-1);
1023   int rt = get_reg(regmap,target);
1024   assert(rs >= 0);
1025   assert(rt >= 0);
1026   uintptr_t host_addr = 0;
1027   void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr);
1028   if (handler == NULL) {
1029     if (addr != host_addr)
1030       emit_movimm_from(addr, rs, host_addr, rs);
1031     switch(type) {
1032       case STOREB_STUB: emit_writebyte_indexed(rt, 0, rs); break;
1033       case STOREH_STUB: emit_writehword_indexed(rt, 0, rs); break;
1034       case STOREW_STUB: emit_writeword_indexed(rt, 0, rs); break;
1035       default:          assert(0);
1036     }
1037     return;
1038   }
1039
1040   // call a memhandler
1041   save_regs(reglist);
1042   //pass_args(rs, rt);
1043   int cc = get_reg(regmap, CCREG);
1044   assert(cc >= 0);
1045   emit_addimm(cc, CLOCK_ADJUST(adj+1), 2);
1046   //emit_movimm((uintptr_t)handler, 3);
1047   // returns new cycle_count
1048
1049   emit_readword(&last_count, HOST_TEMPREG);
1050   emit_writeword(rs, &address); // some handlers still need it
1051   emit_add(2, HOST_TEMPREG, 2);
1052   emit_writeword(2, &Count);
1053   emit_mov(1, 0);
1054   emit_call(handler);
1055   emit_readword(&next_interupt, 0);
1056   emit_readword(&Count, 1);
1057   emit_writeword(0, &last_count);
1058   emit_sub(1, 0, cc);
1059
1060   emit_addimm(cc,-CLOCK_ADJUST(adj+1),cc);
1061   restore_regs(reglist);
1062 }
1063
1064 static void do_unalignedwritestub(int n)
1065 {
1066   assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
1067   assert(0);
1068 }
1069
1070 static void do_invstub(int n)
1071 {
1072   assert(0);
1073 }
1074
1075 void *do_dirty_stub(int i)
1076 {
1077   assem_debug("do_dirty_stub %x\n",start+i*4);
1078   // Careful about the code output here, verify_dirty needs to parse it.
1079   assert(0);
1080   load_regs_entry(i);
1081   return NULL;
1082 }
1083
1084 static void do_dirty_stub_ds()
1085 {
1086   // Careful about the code output here, verify_dirty needs to parse it.
1087   assert(0);
1088 }
1089
1090 /* Special assem */
1091
1092 #define shift_assemble shift_assemble_arm64
1093
1094 static void shift_assemble_arm64(int i,struct regstat *i_regs)
1095 {
1096   assert(0);
1097 }
1098 #define loadlr_assemble loadlr_assemble_arm64
1099
1100 static void loadlr_assemble_arm64(int i,struct regstat *i_regs)
1101 {
1102   assert(0);
1103 }
1104
1105 static void c2op_assemble(int i,struct regstat *i_regs)
1106 {
1107   assert(0);
1108 }
1109
1110 static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
1111 {
1112   assert(0);
1113 }
1114 #define multdiv_assemble multdiv_assemble_arm64
1115
1116 static void do_preload_rhash(u_int r) {
1117   // Don't need this for ARM.  On x86, this puts the value 0xf8 into the
1118   // register.  On ARM the hash can be done with a single instruction (below)
1119 }
1120
1121 static void do_preload_rhtbl(u_int ht) {
1122   emit_addimm(FP, (u_char *)&mini_ht - (u_char *)&dynarec_local, ht);
1123 }
1124
1125 static void do_rhash(u_int rs,u_int rh) {
1126   emit_andimm(rs, 0xf8, rh);
1127 }
1128
1129 static void do_miniht_load(int ht,u_int rh) {
1130   assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
1131   assert(0);
1132 }
1133
1134 static void do_miniht_jump(u_int rs,u_int rh,int ht) {
1135   emit_cmp(rh,rs);
1136   emit_ldreq_indexed(ht,4,15);
1137   //emit_jmp(jump_vaddr_reg[rs]);
1138   assert(0);
1139 }
1140
1141 static void do_miniht_insert(u_int return_address,u_int rt,int temp) {
1142   assert(0);
1143 }
1144
1145 static void mark_clear_cache(void *target)
1146 {
1147   u_long offset = (u_char *)target - translation_cache;
1148   u_int mask = 1u << ((offset >> 12) & 31);
1149   if (!(needs_clear_cache[offset >> 17] & mask)) {
1150     char *start = (char *)((u_long)target & ~4095ul);
1151     start_tcache_write(start, start + 4096);
1152     needs_clear_cache[offset >> 17] |= mask;
1153   }
1154 }
1155
1156 // Clearing the cache is rather slow on ARM Linux, so mark the areas
1157 // that need to be cleared, and then only clear these areas once.
1158 static void do_clear_cache()
1159 {
1160   int i,j;
1161   for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
1162   {
1163     u_int bitmap=needs_clear_cache[i];
1164     if(bitmap) {
1165       u_char *start, *end;
1166       for(j=0;j<32;j++)
1167       {
1168         if(bitmap&(1<<j)) {
1169           start=translation_cache+i*131072+j*4096;
1170           end=start+4095;
1171           j++;
1172           while(j<32) {
1173             if(bitmap&(1<<j)) {
1174               end+=4096;
1175               j++;
1176             }else{
1177               end_tcache_write(start, end);
1178               break;
1179             }
1180           }
1181         }
1182       }
1183       needs_clear_cache[i]=0;
1184     }
1185   }
1186 }
1187
1188 // CPU-architecture-specific initialization
1189 static void arch_init() {
1190 }
1191
1192 // vim:shiftwidth=2:expandtab