drc/gte: add some stall handling
[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) 2009-2018 Gillou68310                                   *
5  *   Copyright (C) 2021 notaz                                              *
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
21  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22
23 #include "pcnt.h"
24 #include "arm_features.h"
25
26 #define CALLER_SAVE_REGS 0x0007ffff
27
28 #define unused __attribute__((unused))
29
30 void do_memhandler_pre();
31 void do_memhandler_post();
32
33 /* Linker */
34 static void set_jump_target(void *addr, void *target)
35 {
36   u_int *ptr = addr;
37   intptr_t offset = (u_char *)target - (u_char *)addr;
38
39   if ((*ptr&0xFC000000) == 0x14000000) { // b
40     assert(offset>=-134217728LL&&offset<134217728LL);
41     *ptr=(*ptr&0xFC000000)|((offset>>2)&0x3ffffff);
42   }
43   else if ((*ptr&0xff000000) == 0x54000000 // b.cond
44         || (*ptr&0x7e000000) == 0x34000000) { // cbz/cbnz
45     // Conditional branch are limited to +/- 1MB
46     // block max size is 256k so branching beyond the +/- 1MB limit
47     // should only happen when jumping to an already compiled block (see add_link)
48     // a workaround would be to do a trampoline jump via a stub at the end of the block
49     assert(-1048576 <= offset && offset < 1048576);
50     *ptr=(*ptr&0xFF00000F)|(((offset>>2)&0x7ffff)<<5);
51   }
52   else if((*ptr&0x9f000000)==0x10000000) { // adr
53     // generated by do_miniht_insert
54     assert(offset>=-1048576LL&&offset<1048576LL);
55     *ptr=(*ptr&0x9F00001F)|(offset&0x3)<<29|((offset>>2)&0x7ffff)<<5;
56   }
57   else
58     abort(); // should not happen
59 }
60
61 // from a pointer to external jump stub (which was produced by emit_extjump2)
62 // find where the jumping insn is
63 static void *find_extjump_insn(void *stub)
64 {
65   int *ptr = (int *)stub + 2;
66   assert((*ptr&0x9f000000) == 0x10000000); // adr
67   int offset = (((signed int)(*ptr<<8)>>13)<<2)|((*ptr>>29)&0x3);
68   return ptr + offset / 4;
69 }
70
71 // find where external branch is liked to using addr of it's stub:
72 // get address that the stub loads (dyna_linker arg1),
73 // treat it as a pointer to branch insn,
74 // return addr where that branch jumps to
75 static void *get_pointer(void *stub)
76 {
77   int *i_ptr = find_extjump_insn(stub);
78   if ((*i_ptr&0xfc000000) == 0x14000000)  // b
79     return i_ptr + ((signed int)(*i_ptr<<6)>>6);
80   if ((*i_ptr&0xff000000) == 0x54000000     // b.cond
81       || (*i_ptr&0x7e000000) == 0x34000000) // cbz/cbnz
82     return i_ptr + ((signed int)(*i_ptr<<8)>>13);
83   assert(0);
84   return NULL;
85 }
86
87 // Allocate a specific ARM register.
88 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
89 {
90   int n;
91   int dirty=0;
92
93   // see if it's already allocated (and dealloc it)
94   for(n=0;n<HOST_REGS;n++)
95   {
96     if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
97       dirty=(cur->dirty>>n)&1;
98       cur->regmap[n]=-1;
99     }
100   }
101
102   cur->regmap[hr]=reg;
103   cur->dirty&=~(1<<hr);
104   cur->dirty|=dirty<<hr;
105   cur->isconst&=~(1<<hr);
106 }
107
108 // Alloc cycle count into dedicated register
109 static void alloc_cc(struct regstat *cur,int i)
110 {
111   alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
112 }
113
114 /* Special alloc */
115
116
117 /* Assembler */
118
119 static unused const char *regname[32] = {
120   "w0",  "w1",  "w2",  "w3",  "w4",  "w5",  "w6",  "w7",
121   "w8",  "w9", "w10", "w11", "w12", "w13", "w14", "w15",
122  "ip0", "ip1", "w18", "w19", "w20", "w21", "w22", "w23",
123  "w24", "w25", "w26", "w27", "w28", "wfp", "wlr", "wsp"
124 };
125
126 static unused const char *regname64[32] = {
127   "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
128   "x8",  "x9", "x10", "x11", "x12", "x13", "x14", "x15",
129  "ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23",
130  "x24", "x25", "x26", "x27", "x28",  "fp",  "lr",  "sp"
131 };
132
133 enum {
134   COND_EQ, COND_NE, COND_CS, COND_CC, COND_MI, COND_PL, COND_VS, COND_VC,
135   COND_HI, COND_LS, COND_GE, COND_LT, COND_GT, COND_LE, COND_AW, COND_NV
136 };
137
138 static unused const char *condname[16] = {
139   "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
140   "hi", "ls", "ge", "lt", "gt", "le", "aw", "nv"
141 };
142
143 static void output_w32(u_int word)
144 {
145   *((u_int *)out) = word;
146   out += 4;
147 }
148
149 static void output_w64(uint64_t dword)
150 {
151   *((uint64_t *)out) = dword;
152   out+=8;
153 }
154
155 /*
156 static u_int rm_rd(u_int rm, u_int rd)
157 {
158   assert(rm < 31);
159   assert(rd < 31);
160   return (rm << 16) | rd;
161 }
162 */
163
164 static u_int rn_rd(u_int rn, u_int rd)
165 {
166   assert(rn < 31);
167   assert(rd < 31);
168   return (rn << 5) | rd;
169 }
170
171 static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
172 {
173   assert(rm < 32);
174   assert(rn < 32);
175   assert(rd < 32);
176   return (rm << 16) | (rn << 5) | rd;
177 }
178
179 static u_int rm_ra_rn_rd(u_int rm, u_int ra, u_int rn, u_int rd)
180 {
181   assert(ra < 32);
182   return rm_rn_rd(rm, rn, rd) | (ra << 10);
183 }
184
185 static u_int imm7_rt2_rn_rt(u_int imm7, u_int rt2, u_int rn, u_int rt)
186 {
187   assert(imm7 < 0x80);
188   assert(rt2 < 31);
189   assert(rn < 32);
190   assert(rt < 31);
191   return (imm7 << 15) | (rt2 << 10) | (rn << 5) | rt;
192 }
193
194 static u_int rm_imm6_rn_rd(u_int rm, u_int imm6, u_int rn, u_int rd)
195 {
196   assert(imm6 <= 63);
197   return rm_rn_rd(rm, rn, rd) | (imm6 << 10);
198 }
199
200 static u_int imm16_rd(u_int imm16, u_int rd)
201 {
202   assert(imm16 < 0x10000);
203   assert(rd < 31);
204   return (imm16 << 5) | rd;
205 }
206
207 static u_int imm12_rn_rd(u_int imm12, u_int rn, u_int rd)
208 {
209   assert(imm12 < 0x1000);
210   assert(rn < 32);
211   assert(rd < 32);
212   return (imm12 << 10) | (rn << 5) | rd;
213 }
214
215 static u_int imm9_rn_rt(u_int imm9, u_int rn, u_int rd)
216 {
217   assert(imm9 < 0x200);
218   assert(rn < 31);
219   assert(rd < 31);
220   return (imm9 << 12) | (rn << 5) | rd;
221 }
222
223 static u_int imm19_rt(u_int imm19, u_int rt)
224 {
225   assert(imm19 < 0x80000);
226   assert(rt < 31);
227   return (imm19 << 5) | rt;
228 }
229
230 static u_int n_immr_imms_rn_rd(u_int n, u_int immr, u_int imms, u_int rn, u_int rd)
231 {
232   assert(n < 2);
233   assert(immr < 0x40);
234   assert(imms < 0x40);
235   assert(rn < 32);
236   assert(rd < 32);
237   return (n << 22) | (immr << 16) | (imms << 10) | (rn << 5) | rd;
238 }
239
240 static u_int genjmp(const u_char *addr)
241 {
242   intptr_t offset = addr - out;
243   if ((uintptr_t)addr < 3) return 0; // a branch that will be patched later
244   if (offset < -134217728 || offset > 134217727) {
245     SysPrintf("%s: out of range: %p %lx\n", __func__, addr, offset);
246     abort();
247     return 0;
248   }
249   return ((u_int)offset >> 2) & 0x03ffffff;
250 }
251
252 static u_int genjmpcc(const u_char *addr)
253 {
254   intptr_t offset = addr - out;
255   if ((uintptr_t)addr < 3) return 0;
256   if (offset < -1048576 || offset > 1048572) {
257     SysPrintf("%s: out of range: %p %lx\n", __func__, addr, offset);
258     abort();
259     return 0;
260   }
261   return ((u_int)offset >> 2) & 0x7ffff;
262 }
263
264 static uint32_t is_mask(u_int value)
265 {
266   return value && ((value + 1) & value) == 0;
267 }
268
269 // This function returns true if the argument contains a
270 // non-empty sequence of ones (possibly rotated) with the remainder zero.
271 static uint32_t is_rotated_mask(u_int value)
272 {
273   if (value == 0 || value == ~0)
274     return 0;
275   if (is_mask((value - 1) | value))
276     return 1;
277   return is_mask((~value - 1) | ~value);
278 }
279
280 static void gen_logical_imm(u_int value, u_int *immr, u_int *imms)
281 {
282   int lzeros, tzeros, ones;
283   assert(value != 0);
284   if (is_mask((value - 1) | value)) {
285     lzeros = __builtin_clz(value);
286     tzeros = __builtin_ctz(value);
287     ones = 32 - lzeros - tzeros;
288     *immr = (32 - tzeros) & 31;
289     *imms = ones - 1;
290     return;
291   }
292   value = ~value;
293   if (is_mask((value - 1) | value)) {
294     lzeros = __builtin_clz(value);
295     tzeros = __builtin_ctz(value);
296     ones = 32 - lzeros - tzeros;
297     *immr = lzeros;
298     *imms = 31 - ones;
299     return;
300   }
301   abort();
302 }
303
304 static void emit_mov(u_int rs, u_int rt)
305 {
306   assem_debug("mov %s,%s\n", regname[rt], regname[rs]);
307   output_w32(0x2a000000 | rm_rn_rd(rs, WZR, rt));
308 }
309
310 static void emit_mov64(u_int rs, u_int rt)
311 {
312   assem_debug("mov %s,%s\n", regname64[rt], regname64[rs]);
313   output_w32(0xaa000000 | rm_rn_rd(rs, WZR, rt));
314 }
315
316 static void emit_add(u_int rs1, u_int rs2, u_int rt)
317 {
318   assem_debug("add %s,%s,%s\n", regname[rt], regname[rs1], regname[rs2]);
319   output_w32(0x0b000000 | rm_rn_rd(rs2, rs1, rt));
320 }
321
322 static void emit_add64(u_int rs1, u_int rs2, u_int rt)
323 {
324   assem_debug("add %s,%s,%s\n", regname64[rt], regname64[rs1], regname64[rs2]);
325   output_w32(0x8b000000 | rm_rn_rd(rs2, rs1, rt));
326 }
327
328 static void emit_adds64(u_int rs1, u_int rs2, u_int rt)
329 {
330   assem_debug("adds %s,%s,%s\n",regname64[rt],regname64[rs1],regname64[rs2]);
331   output_w32(0xab000000 | rm_rn_rd(rs2, rs1, rt));
332 }
333
334 static void emit_neg(u_int rs, u_int rt)
335 {
336   assem_debug("neg %s,%s\n",regname[rt],regname[rs]);
337   output_w32(0x4b000000 | rm_rn_rd(rs, WZR, rt));
338 }
339
340 static void emit_sub(u_int rs1, u_int rs2, u_int rt)
341 {
342   assem_debug("sub %s,%s,%s\n", regname[rt], regname[rs1], regname[rs2]);
343   output_w32(0x4b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
344 }
345
346 static void emit_sub_asrimm(u_int rs1, u_int rs2, u_int shift, u_int rt)
347 {
348   assem_debug("sub %s,%s,%s,asr #%u\n",regname[rt],regname[rs1],regname[rs2],shift);
349   output_w32(0x4b800000 | rm_imm6_rn_rd(rs2, shift, rs1, rt));
350 }
351
352 static void emit_movz(u_int imm, u_int rt)
353 {
354   assem_debug("movz %s,#%#x\n", regname[rt], imm);
355   output_w32(0x52800000 | imm16_rd(imm, rt));
356 }
357
358 static void emit_movz_lsl16(u_int imm, u_int rt)
359 {
360   assem_debug("movz %s,#%#x,lsl #16\n", regname[rt], imm);
361   output_w32(0x52a00000 | imm16_rd(imm, rt));
362 }
363
364 static void emit_movn(u_int imm, u_int rt)
365 {
366   assem_debug("movn %s,#%#x\n", regname[rt], imm);
367   output_w32(0x12800000 | imm16_rd(imm, rt));
368 }
369
370 static void emit_movn_lsl16(u_int imm,u_int rt)
371 {
372   assem_debug("movn %s,#%#x,lsl #16\n", regname[rt], imm);
373   output_w32(0x12a00000 | imm16_rd(imm, rt));
374 }
375
376 static void emit_movk(u_int imm,u_int rt)
377 {
378   assem_debug("movk %s,#%#x\n", regname[rt], imm);
379   output_w32(0x72800000 | imm16_rd(imm, rt));
380 }
381
382 static void emit_movk_lsl16(u_int imm,u_int rt)
383 {
384   assert(imm<65536);
385   assem_debug("movk %s,#%#x,lsl #16\n", regname[rt], imm);
386   output_w32(0x72a00000 | imm16_rd(imm, rt));
387 }
388
389 static void emit_zeroreg(u_int rt)
390 {
391   emit_movz(0, rt);
392 }
393
394 static void emit_movimm(u_int imm, u_int rt)
395 {
396   if (imm < 65536)
397     emit_movz(imm, rt);
398   else if ((~imm) < 65536)
399     emit_movn(~imm, rt);
400   else if ((imm&0xffff) == 0)
401     emit_movz_lsl16(imm >> 16, rt);
402   else if (((~imm)&0xffff) == 0)
403     emit_movn_lsl16(~imm >> 16, rt);
404   else if (is_rotated_mask(imm)) {
405     u_int immr, imms;
406     gen_logical_imm(imm, &immr, &imms);
407     assem_debug("orr %s,wzr,#%#x\n", regname[rt], imm);
408     output_w32(0x32000000 | n_immr_imms_rn_rd(0, immr, imms, WZR, rt));
409   }
410   else {
411     emit_movz(imm & 0xffff, rt);
412     emit_movk_lsl16(imm >> 16, rt);
413   }
414 }
415
416 static void emit_readword(void *addr, u_int rt)
417 {
418   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
419   if (!(offset & 3) && offset <= 16380) {
420     assem_debug("ldr %s,[x%d+%#lx]\n", regname[rt], FP, offset);
421     output_w32(0xb9400000 | imm12_rn_rd(offset >> 2, FP, rt));
422   }
423   else
424     abort();
425 }
426
427 static void emit_readdword(void *addr, u_int rt)
428 {
429   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
430   if (!(offset & 7) && offset <= 32760) {
431     assem_debug("ldr %s,[x%d+%#lx]\n", regname64[rt], FP, offset);
432     output_w32(0xf9400000 | imm12_rn_rd(offset >> 3, FP, rt));
433   }
434   else
435     abort();
436 }
437
438 static void emit_readshword(void *addr, u_int rt)
439 {
440   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
441   if (!(offset & 1) && offset <= 8190) {
442     assem_debug("ldrsh %s,[x%d+%#lx]\n", regname[rt], FP, offset);
443     output_w32(0x79c00000 | imm12_rn_rd(offset >> 1, FP, rt));
444   }
445   else
446     assert(0);
447 }
448
449 static void emit_loadreg(u_int r, u_int hr)
450 {
451   int is64 = 0;
452   assert(r < 64);
453   if (r == 0)
454     emit_zeroreg(hr);
455   else {
456     void *addr = &psxRegs.GPR.r[r];
457     switch (r) {
458     //case HIREG: addr = &hi; break;
459     //case LOREG: addr = &lo; break;
460     case CCREG: addr = &cycle_count; break;
461     case CSREG: addr = &Status; break;
462     case INVCP: addr = &invc_ptr; is64 = 1; break;
463     default: assert(r < 34); break;
464     }
465     if (is64)
466       emit_readdword(addr, hr);
467     else
468       emit_readword(addr, hr);
469   }
470 }
471
472 static void emit_writeword(u_int rt, void *addr)
473 {
474   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
475   if (!(offset & 3) && offset <= 16380) {
476     assem_debug("str %s,[x%d+%#lx]\n", regname[rt], FP, offset);
477     output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, FP, rt));
478   }
479   else
480     assert(0);
481 }
482
483 static void emit_writedword(u_int rt, void *addr)
484 {
485   uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
486   if (!(offset & 7) && offset <= 32760) {
487     assem_debug("str %s,[x%d+%#lx]\n", regname64[rt], FP, offset);
488     output_w32(0xf9000000 | imm12_rn_rd(offset >> 3, FP, rt));
489   }
490   else
491     abort();
492 }
493
494 static void emit_storereg(u_int r, u_int hr)
495 {
496   assert(r < 64);
497   void *addr = &psxRegs.GPR.r[r];
498   switch (r) {
499   //case HIREG: addr = &hi; break;
500   //case LOREG: addr = &lo; break;
501   case CCREG: addr = &cycle_count; break;
502   default: assert(r < 34); break;
503   }
504   emit_writeword(hr, addr);
505 }
506
507 static void emit_test(u_int rs, u_int rt)
508 {
509   assem_debug("tst %s,%s\n", regname[rs], regname[rt]);
510   output_w32(0x6a000000 | rm_rn_rd(rt, rs, WZR));
511 }
512
513 static void emit_testimm(u_int rs, u_int imm)
514 {
515   u_int immr, imms;
516   assem_debug("tst %s,#%#x\n", regname[rs], imm);
517   assert(is_rotated_mask(imm)); // good enough for PCSX
518   gen_logical_imm(imm, &immr, &imms);
519   output_w32(0x72000000 | n_immr_imms_rn_rd(0, immr, imms, rs, WZR));
520 }
521
522 static void emit_not(u_int rs,u_int rt)
523 {
524   assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
525   output_w32(0x2a200000 | rm_rn_rd(rs, WZR, rt));
526 }
527
528 static void emit_and(u_int rs1,u_int rs2,u_int rt)
529 {
530   assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
531   output_w32(0x0a000000 | rm_rn_rd(rs2, rs1, rt));
532 }
533
534 static void emit_or(u_int rs1,u_int rs2,u_int rt)
535 {
536   assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
537   output_w32(0x2a000000 | rm_rn_rd(rs2, rs1, rt));
538 }
539
540 static void emit_bic(u_int rs1,u_int rs2,u_int rt)
541 {
542   assem_debug("bic %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
543   output_w32(0x0a200000 | rm_rn_rd(rs2, rs1, rt));
544 }
545
546 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
547 {
548   assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
549   output_w32(0x2a000000 | rm_imm6_rn_rd(rs, imm, rt, rt));
550 }
551
552 static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
553 {
554   assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
555   output_w32(0x2a400000 | rm_imm6_rn_rd(rs, imm, rt, rt));
556 }
557
558 static void emit_bicsar_imm(u_int rs,u_int imm,u_int rt)
559 {
560   assem_debug("bic %s,%s,%s,asr #%d\n",regname[rt],regname[rt],regname[rs],imm);
561   output_w32(0x0aa00000 | rm_imm6_rn_rd(rs, imm, rt, rt));
562 }
563
564 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
565 {
566   assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
567   output_w32(0x4a000000 | rm_rn_rd(rs2, rs1, rt));
568 }
569
570 static void emit_xorsar_imm(u_int rs1, u_int rs2, u_int imm, u_int rt)
571 {
572   assem_debug("eor %s,%s,%s,asr #%d\n",regname[rt],regname[rs1],regname[rs2],imm);
573   output_w32(0x4a800000 | rm_imm6_rn_rd(rs2, imm, rs1, rt));
574 }
575
576 static void emit_addimm_s(u_int s, u_int is64, u_int rs, uintptr_t imm, u_int rt)
577 {
578   unused const char *st = s ? "s" : "";
579   s = s ? 0x20000000 : 0;
580   is64 = is64 ? 0x80000000 : 0;
581   if (imm < 4096) {
582     assem_debug("add%s %s,%s,%#lx\n", st, regname[rt], regname[rs], imm);
583     output_w32(0x11000000 | is64 | s | imm12_rn_rd(imm, rs, rt));
584   }
585   else if (-imm < 4096) {
586     assem_debug("sub%s %s,%s,%#lx\n", st, regname[rt], regname[rs], -imm);
587     output_w32(0x51000000 | is64 | s | imm12_rn_rd(-imm, rs, rt));
588   }
589   else if (imm < 16777216) {
590     assem_debug("add %s,%s,#%#lx\n",regname[rt],regname[rt],imm&0xfff000);
591     output_w32(0x11400000 | is64 | imm12_rn_rd(imm >> 12, rs, rt));
592     if ((imm & 0xfff) || s) {
593       assem_debug("add%s %s,%s,#%#lx\n",st,regname[rt],regname[rs],imm&0xfff);
594       output_w32(0x11000000 | is64 | s | imm12_rn_rd(imm & 0xfff, rt, rt));
595     }
596   }
597   else if (-imm < 16777216) {
598     assem_debug("sub %s,%s,#%#lx\n",regname[rt],regname[rt],-imm&0xfff000);
599     output_w32(0x51400000 | is64 | imm12_rn_rd(-imm >> 12, rs, rt));
600     if ((imm & 0xfff) || s) {
601       assem_debug("sub%s %s,%s,#%#lx\n",st,regname[rt],regname[rs],-imm&0xfff);
602       output_w32(0x51000000 | is64 | s | imm12_rn_rd(-imm & 0xfff, rt, rt));
603     }
604   }
605   else
606     abort();
607 }
608
609 static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
610 {
611   emit_addimm_s(0, 0, rs, imm, rt);
612 }
613
614 static void emit_addimm64(u_int rs, uintptr_t imm, u_int rt)
615 {
616   emit_addimm_s(0, 1, rs, imm, rt);
617 }
618
619 static void emit_addimm_and_set_flags(int imm, u_int rt)
620 {
621   emit_addimm_s(1, 0, rt, imm, rt);
622 }
623
624 static void emit_addimm_no_flags(u_int imm,u_int rt)
625 {
626   emit_addimm(rt,imm,rt);
627 }
628
629 static void emit_logicop_imm(u_int op, u_int rs, u_int imm, u_int rt)
630 {
631   const char *names[] = { "and", "orr", "eor", "ands" };
632   const char *name = names[op];
633   u_int immr, imms;
634   op = op << 29;
635   if (is_rotated_mask(imm)) {
636     gen_logical_imm(imm, &immr, &imms);
637     assem_debug("%s %s,%s,#%#x\n", name, regname[rt], regname[rs], imm);
638     output_w32(op | 0x12000000 | n_immr_imms_rn_rd(0, immr, imms, rs, rt));
639   }
640   else {
641     if (rs == HOST_TEMPREG || rt != HOST_TEMPREG)
642       host_tempreg_acquire();
643     emit_movimm(imm, HOST_TEMPREG);
644     assem_debug("%s %s,%s,%s\n", name, regname[rt], regname[rs], regname[HOST_TEMPREG]);
645     output_w32(op | 0x0a000000 | rm_rn_rd(HOST_TEMPREG, rs, rt));
646     if (rs == HOST_TEMPREG || rt != HOST_TEMPREG)
647       host_tempreg_release();
648   }
649   (void)name;
650 }
651
652 static void emit_andimm(u_int rs, u_int imm, u_int rt)
653 {
654   if (imm == 0)
655     emit_zeroreg(rt);
656   else
657     emit_logicop_imm(0, rs, imm, rt);
658 }
659
660 static void emit_orimm(u_int rs, u_int imm, u_int rt)
661 {
662   if (imm == 0) {
663     if (rs != rt)
664       emit_mov(rs, rt);
665   }
666   else
667     emit_logicop_imm(1, rs, imm, rt);
668 }
669
670 static void emit_xorimm(u_int rs, u_int imm, u_int rt)
671 {
672   if (imm == 0) {
673     if (rs != rt)
674       emit_mov(rs, rt);
675   }
676   else
677     emit_logicop_imm(2, rs, imm, rt);
678 }
679
680 static void emit_sbfm(u_int rs,u_int imm,u_int rt)
681 {
682   assem_debug("sbfm %s,%s,#0,#%d\n",regname[rt],regname[rs],imm);
683   output_w32(0x13000000 | n_immr_imms_rn_rd(0, 0, imm, rs, rt));
684 }
685
686 static void emit_ubfm(u_int rs,u_int imm,u_int rt)
687 {
688   assem_debug("ubfm %s,%s,#0,#%d\n",regname[rt],regname[rs],imm);
689   output_w32(0x53000000 | n_immr_imms_rn_rd(0, 0, imm, rs, rt));
690 }
691
692 static void emit_shlimm(u_int rs,u_int imm,u_int rt)
693 {
694   assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
695   output_w32(0x53000000 | n_immr_imms_rn_rd(0, (31-imm)+1, 31-imm, rs, rt));
696 }
697
698 static void emit_shrimm(u_int rs,u_int imm,u_int rt)
699 {
700   assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
701   output_w32(0x53000000 | n_immr_imms_rn_rd(0, imm, 31, rs, rt));
702 }
703
704 static void emit_shrimm64(u_int rs,u_int imm,u_int rt)
705 {
706   assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
707   output_w32(0xd3400000 | n_immr_imms_rn_rd(0, imm, 63, rs, rt));
708 }
709
710 static void emit_sarimm(u_int rs,u_int imm,u_int rt)
711 {
712   assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
713   output_w32(0x13000000 | n_immr_imms_rn_rd(0, imm, 31, rs, rt));
714 }
715
716 static void emit_rorimm(u_int rs,u_int imm,u_int rt)
717 {
718   assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
719   output_w32(0x13800000 | rm_imm6_rn_rd(rs, imm, rs, rt));
720 }
721
722 static void emit_signextend16(u_int rs, u_int rt)
723 {
724   assem_debug("sxth %s,%s\n", regname[rt], regname[rs]);
725   output_w32(0x13000000 | n_immr_imms_rn_rd(0, 0, 15, rs, rt));
726 }
727
728 static void emit_shl(u_int rs,u_int rshift,u_int rt)
729 {
730   assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[rshift]);
731   output_w32(0x1ac02000 | rm_rn_rd(rshift, rs, rt));
732 }
733
734 static void emit_shr(u_int rs,u_int rshift,u_int rt)
735 {
736   assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[rshift]);
737   output_w32(0x1ac02400 | rm_rn_rd(rshift, rs, rt));
738 }
739
740 static void emit_sar(u_int rs,u_int rshift,u_int rt)
741 {
742   assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[rshift]);
743   output_w32(0x1ac02800 | rm_rn_rd(rshift, rs, rt));
744 }
745
746 static void emit_cmpimm(u_int rs, u_int imm)
747 {
748   if (imm < 4096) {
749     assem_debug("cmp %s,%#x\n", regname[rs], imm);
750     output_w32(0x71000000 | imm12_rn_rd(imm, rs, WZR));
751   }
752   else if (-imm < 4096) {
753     assem_debug("cmn %s,%#x\n", regname[rs], imm);
754     output_w32(0x31000000 | imm12_rn_rd(-imm, rs, WZR));
755   }
756   else if (imm < 16777216 && !(imm & 0xfff)) {
757     assem_debug("cmp %s,#%#x\n", regname[rs], imm);
758     output_w32(0x71400000 | imm12_rn_rd(imm >> 12, rs, WZR));
759   }
760   else {
761     host_tempreg_acquire();
762     emit_movimm(imm, HOST_TEMPREG);
763     assem_debug("cmp %s,%s\n", regname[rs], regname[HOST_TEMPREG]);
764     output_w32(0x6b000000 | rm_rn_rd(HOST_TEMPREG, rs, WZR));
765     host_tempreg_release();
766   }
767 }
768
769 static void emit_cmov_imm(u_int cond0, u_int cond1, u_int imm, u_int rt)
770 {
771   assert(imm == 0 || imm == 1);
772   assert(cond0 < 0x10);
773   assert(cond1 < 0x10);
774   if (imm) {
775     assem_debug("csinc %s,%s,%s,%s\n",regname[rt],regname[rt],regname[WZR],condname[cond1]);
776     output_w32(0x1a800400 | (cond1 << 12) | rm_rn_rd(WZR, rt, rt));
777   } else {
778     assem_debug("csel %s,%s,%s,%s\n",regname[rt],regname[WZR],regname[rt],condname[cond0]);
779     output_w32(0x1a800000 | (cond0 << 12) | rm_rn_rd(rt, WZR, rt));
780   }
781 }
782
783 static void emit_cmovne_imm(u_int imm,u_int rt)
784 {
785   emit_cmov_imm(COND_NE, COND_EQ, imm, rt);
786 }
787
788 static void emit_cmovl_imm(u_int imm,u_int rt)
789 {
790   emit_cmov_imm(COND_LT, COND_GE, imm, rt);
791 }
792
793 static void emit_cmovb_imm(int imm,u_int rt)
794 {
795   emit_cmov_imm(COND_CC, COND_CS, imm, rt);
796 }
797
798 static void emit_cmoveq_reg(u_int rs,u_int rt)
799 {
800   assem_debug("csel %s,%s,%s,eq\n",regname[rt],regname[rs],regname[rt]);
801   output_w32(0x1a800000 | (COND_EQ << 12) | rm_rn_rd(rt, rs, rt));
802 }
803
804 static void emit_cmovne_reg(u_int rs,u_int rt)
805 {
806   assem_debug("csel %s,%s,%s,ne\n",regname[rt],regname[rs],regname[rt]);
807   output_w32(0x1a800000 | (COND_NE << 12) | rm_rn_rd(rt, rs, rt));
808 }
809
810 static void emit_cmovl_reg(u_int rs,u_int rt)
811 {
812   assem_debug("csel %s,%s,%s,lt\n",regname[rt],regname[rs],regname[rt]);
813   output_w32(0x1a800000 | (COND_LT << 12) | rm_rn_rd(rt, rs, rt));
814 }
815
816 static void emit_cmovs_reg(u_int rs,u_int rt)
817 {
818   assem_debug("csel %s,%s,%s,mi\n",regname[rt],regname[rs],regname[rt]);
819   output_w32(0x1a800000 | (COND_MI << 12) | rm_rn_rd(rt, rs, rt));
820 }
821
822 static void emit_csinvle_reg(u_int rs1,u_int rs2,u_int rt)
823 {
824   assem_debug("csinv %s,%s,%s,le\n",regname[rt],regname[rs1],regname[rs2]);
825   output_w32(0x5a800000 | (COND_LE << 12) | rm_rn_rd(rs2, rs1, rt));
826 }
827
828 static void emit_slti32(u_int rs,int imm,u_int rt)
829 {
830   if(rs!=rt) emit_zeroreg(rt);
831   emit_cmpimm(rs,imm);
832   if(rs==rt) emit_movimm(0,rt);
833   emit_cmovl_imm(1,rt);
834 }
835
836 static void emit_sltiu32(u_int rs,int imm,u_int rt)
837 {
838   if(rs!=rt) emit_zeroreg(rt);
839   emit_cmpimm(rs,imm);
840   if(rs==rt) emit_movimm(0,rt);
841   emit_cmovb_imm(1,rt);
842 }
843
844 static void emit_cmp(u_int rs,u_int rt)
845 {
846   assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
847   output_w32(0x6b000000 | rm_rn_rd(rt, rs, WZR));
848 }
849
850 static void emit_set_gz32(u_int rs, u_int rt)
851 {
852   //assem_debug("set_gz32\n");
853   emit_cmpimm(rs,1);
854   emit_movimm(1,rt);
855   emit_cmovl_imm(0,rt);
856 }
857
858 static void emit_set_nz32(u_int rs, u_int rt)
859 {
860   //assem_debug("set_nz32\n");
861   if(rs!=rt) emit_mov(rs,rt);
862   emit_test(rs,rs);
863   emit_cmovne_imm(1,rt);
864 }
865
866 static void emit_set_if_less32(u_int rs1, u_int rs2, u_int rt)
867 {
868   //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
869   if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
870   emit_cmp(rs1,rs2);
871   if(rs1==rt||rs2==rt) emit_movimm(0,rt);
872   emit_cmovl_imm(1,rt);
873 }
874
875 static void emit_set_if_carry32(u_int rs1, u_int rs2, u_int rt)
876 {
877   //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
878   if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
879   emit_cmp(rs1,rs2);
880   if(rs1==rt||rs2==rt) emit_movimm(0,rt);
881   emit_cmovb_imm(1,rt);
882 }
883
884 static int can_jump_or_call(const void *a)
885 {
886   intptr_t diff = (u_char *)a - out;
887   return (-134217728 <= diff && diff <= 134217727);
888 }
889
890 static void emit_call(const void *a)
891 {
892   intptr_t diff = (u_char *)a - out;
893   assem_debug("bl %p (%p+%lx)%s\n", a, out, diff, func_name(a));
894   assert(!(diff & 3));
895   if (-134217728 <= diff && diff <= 134217727)
896     output_w32(0x94000000 | ((diff >> 2) & 0x03ffffff));
897   else
898     abort();
899 }
900
901 static void emit_jmp(const void *a)
902 {
903   assem_debug("b %p (%p+%lx)%s\n", a, out, (u_char *)a - out, func_name(a));
904   u_int offset = genjmp(a);
905   output_w32(0x14000000 | offset);
906 }
907
908 static void emit_jne(const void *a)
909 {
910   assem_debug("bne %p\n", a);
911   u_int offset = genjmpcc(a);
912   output_w32(0x54000000 | (offset << 5) | COND_NE);
913 }
914
915 static void emit_jeq(const void *a)
916 {
917   assem_debug("beq %p\n", a);
918   u_int offset = genjmpcc(a);
919   output_w32(0x54000000 | (offset << 5) | COND_EQ);
920 }
921
922 static void emit_js(const void *a)
923 {
924   assem_debug("bmi %p\n", a);
925   u_int offset = genjmpcc(a);
926   output_w32(0x54000000 | (offset << 5) | COND_MI);
927 }
928
929 static void emit_jns(const void *a)
930 {
931   assem_debug("bpl %p\n", a);
932   u_int offset = genjmpcc(a);
933   output_w32(0x54000000 | (offset << 5) | COND_PL);
934 }
935
936 static void emit_jl(const void *a)
937 {
938   assem_debug("blt %p\n", a);
939   u_int offset = genjmpcc(a);
940   output_w32(0x54000000 | (offset << 5) | COND_LT);
941 }
942
943 static void emit_jge(const void *a)
944 {
945   assem_debug("bge %p\n", a);
946   u_int offset = genjmpcc(a);
947   output_w32(0x54000000 | (offset << 5) | COND_GE);
948 }
949
950 static void emit_jno(const void *a)
951 {
952   assem_debug("bvc %p\n", a);
953   u_int offset = genjmpcc(a);
954   output_w32(0x54000000 | (offset << 5) | COND_VC);
955 }
956
957 static void emit_jc(const void *a)
958 {
959   assem_debug("bcs %p\n", a);
960   u_int offset = genjmpcc(a);
961   output_w32(0x54000000 | (offset << 5) | COND_CS);
962 }
963
964 static void emit_cb(u_int isnz, u_int is64, const void *a, u_int r)
965 {
966   assem_debug("cb%sz %s,%p\n", isnz?"n":"", is64?regname64[r]:regname[r], a);
967   u_int offset = genjmpcc(a);
968   is64 = is64 ? 0x80000000 : 0;
969   isnz = isnz ? 0x01000000 : 0;
970   output_w32(0x34000000 | is64 | isnz | imm19_rt(offset, r));
971 }
972
973 static void emit_cbz(const void *a, u_int r)
974 {
975   emit_cb(0, 0, a, r);
976 }
977
978 static void emit_jmpreg(u_int r)
979 {
980   assem_debug("br %s\n", regname64[r]);
981   output_w32(0xd61f0000 | rm_rn_rd(0, r, 0));
982 }
983
984 static void emit_retreg(u_int r)
985 {
986   assem_debug("ret %s\n", r == LR ? "" : regname64[r]);
987   output_w32(0xd65f0000 | rm_rn_rd(0, r, 0));
988 }
989
990 static void emit_ret(void)
991 {
992   emit_retreg(LR);
993 }
994
995 static void emit_adr(void *addr, u_int rt)
996 {
997   intptr_t offset = (u_char *)addr - out;
998   assert(-1048576 <= offset && offset < 1048576);
999   assert(rt < 31);
1000   assem_debug("adr x%d,#%#lx\n", rt, offset);
1001   output_w32(0x10000000 | ((offset&0x3) << 29) | (((offset>>2)&0x7ffff) << 5) | rt);
1002 }
1003
1004 static void emit_adrp(void *addr, u_int rt)
1005 {
1006   intptr_t offset = ((intptr_t)addr & ~0xfffl) - ((intptr_t)out & ~0xfffl);
1007   assert(-4294967296l <= offset && offset < 4294967296l);
1008   assert(rt < 31);
1009   offset >>= 12;
1010   assem_debug("adrp %s,#%#lx(000)\n",regname64[rt],offset);
1011   output_w32(0x90000000 | ((offset&0x3)<<29) | (((offset>>2)&0x7ffff)<<5) | rt);
1012 }
1013
1014 static void emit_readword_indexed(int offset, u_int rs, u_int rt)
1015 {
1016   assem_debug("ldur %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
1017   assert(-256 <= offset && offset < 256);
1018   output_w32(0xb8400000 | imm9_rn_rt(offset&0x1ff, rs, rt));
1019 }
1020
1021 static void emit_strb_dualindexed(u_int rs1, u_int rs2, u_int rt)
1022 {
1023   assem_debug("strb %s, [%s,%s]\n",regname[rt],regname64[rs1],regname[rs2]);
1024   output_w32(0x38204800 | rm_rn_rd(rs2, rs1, rt));
1025 }
1026
1027 static void emit_strh_dualindexed(u_int rs1, u_int rs2, u_int rt)
1028 {
1029   assem_debug("strh %s, [%s,%s]\n",regname[rt],regname64[rs1],regname[rs2]);
1030   output_w32(0x78204800 | rm_rn_rd(rs2, rs1, rt));
1031 }
1032
1033 static void emit_str_dualindexed(u_int rs1, u_int rs2, u_int rt)
1034 {
1035   assem_debug("str %s, [%s,%s]\n",regname[rt],regname64[rs1],regname[rs2]);
1036   output_w32(0xb8204800 | rm_rn_rd(rs2, rs1, rt));
1037 }
1038
1039 static void emit_readdword_dualindexedx8(u_int rs1, u_int rs2, u_int rt)
1040 {
1041   assem_debug("ldr %s, [%s,%s, uxtw #3]\n",regname64[rt],regname64[rs1],regname[rs2]);
1042   output_w32(0xf8605800 | rm_rn_rd(rs2, rs1, rt));
1043 }
1044
1045 static void emit_ldrb_dualindexed(u_int rs1, u_int rs2, u_int rt)
1046 {
1047   assem_debug("ldrb %s, [%s,%s]\n",regname[rt],regname64[rs1],regname[rs2]);
1048   output_w32(0x38604800 | rm_rn_rd(rs2, rs1, rt));
1049 }
1050
1051 static void emit_ldrsb_dualindexed(u_int rs1, u_int rs2, u_int rt)
1052 {
1053   assem_debug("ldrsb %s, [%s,%s]\n",regname[rt],regname64[rs1],regname[rs2]);
1054   output_w32(0x38a04800 | rm_rn_rd(rs2, rs1, rt));
1055 }
1056
1057 static void emit_ldrh_dualindexed(u_int rs1, u_int rs2, u_int rt)
1058 {
1059   assem_debug("ldrh %s, [%s,%s, uxtw]\n",regname[rt],regname64[rs1],regname[rs2]);
1060   output_w32(0x78604800 | rm_rn_rd(rs2, rs1, rt));
1061 }
1062
1063 static void emit_ldrsh_dualindexed(u_int rs1, u_int rs2, u_int rt)
1064 {
1065   assem_debug("ldrsh %s, [%s,%s, uxtw]\n",regname[rt],regname64[rs1],regname[rs2]);
1066   output_w32(0x78a04800 | rm_rn_rd(rs2, rs1, rt));
1067 }
1068
1069 static void emit_ldr_dualindexed(u_int rs1, u_int rs2, u_int rt)
1070 {
1071   assem_debug("ldr %s, [%s,%s, uxtw]\n",regname[rt],regname64[rs1],regname[rs2]);
1072   output_w32(0xb8604800 | rm_rn_rd(rs2, rs1, rt));
1073 }
1074
1075 static void emit_movsbl_indexed(int offset, u_int rs, u_int rt)
1076 {
1077   assem_debug("ldursb %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
1078   assert(-256 <= offset && offset < 256);
1079   output_w32(0x38c00000 | imm9_rn_rt(offset&0x1ff, rs, rt));
1080 }
1081
1082 static void emit_movswl_indexed(int offset, u_int rs, u_int rt)
1083 {
1084   assem_debug("ldursh %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
1085   assert(-256 <= offset && offset < 256);
1086   output_w32(0x78c00000 | imm9_rn_rt(offset&0x1ff, rs, rt));
1087 }
1088
1089 static void emit_movzbl_indexed(int offset, u_int rs, u_int rt)
1090 {
1091   assem_debug("ldurb %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
1092   assert(-256 <= offset && offset < 256);
1093   output_w32(0x38400000 | imm9_rn_rt(offset&0x1ff, rs, rt));
1094 }
1095
1096 static void emit_movzwl_indexed(int offset, u_int rs, u_int rt)
1097 {
1098   assem_debug("ldurh %s,[%s+%#x]\n",regname[rt],regname64[rs],offset);
1099   assert(-256 <= offset && offset < 256);
1100   output_w32(0x78400000 | imm9_rn_rt(offset&0x1ff, rs, rt));
1101 }
1102
1103 static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
1104 {
1105   if (!(offset & 3) && (u_int)offset <= 16380) {
1106     assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
1107     output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt));
1108   }
1109   else if (-256 <= offset && offset < 256) {
1110     assem_debug("stur %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
1111     output_w32(0xb8000000 | imm9_rn_rt(offset & 0x1ff, rs, rt));
1112   }
1113   else
1114     assert(0);
1115 }
1116
1117 static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
1118 {
1119   if (!(offset & 1) && (u_int)offset <= 8190) {
1120     assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
1121     output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt));
1122   }
1123   else if (-256 <= offset && offset < 256) {
1124     assem_debug("sturh %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
1125     output_w32(0x78000000 | imm9_rn_rt(offset & 0x1ff, rs, rt));
1126   }
1127   else
1128     assert(0);
1129 }
1130
1131 static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
1132 {
1133   if ((u_int)offset < 4096) {
1134     assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
1135     output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt));
1136   }
1137   else if (-256 <= offset && offset < 256) {
1138     assem_debug("sturb %s,[%s+%#x]\n", regname[rt], regname64[rs], offset);
1139     output_w32(0x38000000 | imm9_rn_rt(offset & 0x1ff, rs, rt));
1140   }
1141   else
1142     assert(0);
1143 }
1144
1145 static void emit_umull(u_int rs1, u_int rs2, u_int rt)
1146 {
1147   assem_debug("umull %s,%s,%s\n",regname64[rt],regname[rs1],regname[rs2]);
1148   output_w32(0x9ba00000 | rm_ra_rn_rd(rs2, WZR, rs1, rt));
1149 }
1150
1151 static void emit_smull(u_int rs1, u_int rs2, u_int rt)
1152 {
1153   assem_debug("smull %s,%s,%s\n",regname64[rt],regname[rs1],regname[rs2]);
1154   output_w32(0x9b200000 | rm_ra_rn_rd(rs2, WZR, rs1, rt));
1155 }
1156
1157 static void emit_msub(u_int rs1, u_int rs2, u_int rs3, u_int rt)
1158 {
1159   assem_debug("msub %s,%s,%s,%s\n",regname[rt],regname[rs1],regname[rs2],regname[rs3]);
1160   output_w32(0x1b008000 | rm_ra_rn_rd(rs2, rs3, rs1, rt));
1161 }
1162
1163 static void emit_sdiv(u_int rs1, u_int rs2, u_int rt)
1164 {
1165   assem_debug("sdiv %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1166   output_w32(0x1ac00c00 | rm_rn_rd(rs2, rs1, rt));
1167 }
1168
1169 static void emit_udiv(u_int rs1, u_int rs2, u_int rt)
1170 {
1171   assem_debug("udiv %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
1172   output_w32(0x1ac00800 | rm_rn_rd(rs2, rs1, rt));
1173 }
1174
1175 static void emit_clz(u_int rs, u_int rt)
1176 {
1177   assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
1178   output_w32(0x5ac01000 | rn_rd(rs, rt));
1179 }
1180
1181 // special case for checking invalid_code
1182 static void emit_cmpmem_indexedsr12_reg(u_int rbase, u_int r, u_int imm)
1183 {
1184   host_tempreg_acquire();
1185   emit_shrimm(r, 12, HOST_TEMPREG);
1186   assem_debug("ldrb %s,[%s,%s,uxtw]\n",regname[HOST_TEMPREG],regname64[rbase],regname[HOST_TEMPREG]);
1187   output_w32(0x38604800 | rm_rn_rd(HOST_TEMPREG, rbase, HOST_TEMPREG));
1188   emit_cmpimm(HOST_TEMPREG, imm);
1189   host_tempreg_release();
1190 }
1191
1192 // special for loadlr_assemble, rs2 is destroyed
1193 static void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt)
1194 {
1195   emit_shl(rs2, shift, rs2);
1196   emit_bic(rs1, rs2, rt);
1197 }
1198
1199 static void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt)
1200 {
1201   emit_shr(rs2, shift, rs2);
1202   emit_bic(rs1, rs2, rt);
1203 }
1204
1205 static void emit_loadlp_ofs(u_int ofs, u_int rt)
1206 {
1207   output_w32(0x58000000 | imm19_rt(ofs, rt));
1208 }
1209
1210 static void emit_ldst(int is_st, int is64, u_int rt, u_int rn, u_int ofs)
1211 {
1212   u_int op = 0xb9000000;
1213   unused const char *ldst = is_st ? "st" : "ld";
1214   unused char rp = is64 ? 'x' : 'w';
1215   assem_debug("%sr %c%d,[x%d,#%#x]\n", ldst, rp, rt, rn, ofs);
1216   is64 = is64 ? 1 : 0;
1217   assert((ofs & ((1 << (2+is64)) - 1)) == 0);
1218   ofs = (ofs >> (2+is64));
1219   if (!is_st) op |= 0x00400000;
1220   if (is64)   op |= 0x40000000;
1221   output_w32(op | imm12_rn_rd(ofs, rn, rt));
1222 }
1223
1224 static void emit_ldstp(int is_st, int is64, u_int rt1, u_int rt2, u_int rn, int ofs)
1225 {
1226   u_int op = 0x29000000;
1227   unused const char *ldst = is_st ? "st" : "ld";
1228   unused char rp = is64 ? 'x' : 'w';
1229   assem_debug("%sp %c%d,%c%d,[x%d,#%#x]\n", ldst, rp, rt1, rp, rt2, rn, ofs);
1230   is64 = is64 ? 1 : 0;
1231   assert((ofs & ((1 << (2+is64)) - 1)) == 0);
1232   ofs = (ofs >> (2+is64));
1233   assert(-64 <= ofs && ofs <= 63);
1234   ofs &= 0x7f;
1235   if (!is_st) op |= 0x00400000;
1236   if (is64)   op |= 0x80000000;
1237   output_w32(op | imm7_rt2_rn_rt(ofs, rt2, rn, rt1));
1238 }
1239
1240 static void save_load_regs_all(int is_store, u_int reglist)
1241 {
1242   int ofs = 0, c = 0;
1243   u_int r, pair[2];
1244   for (r = 0; reglist; r++, reglist >>= 1) {
1245     if (reglist & 1)
1246       pair[c++] = r;
1247     if (c == 2) {
1248       emit_ldstp(is_store, 1, pair[0], pair[1], SP, SSP_CALLEE_REGS + ofs);
1249       ofs += 8 * 2;
1250       c = 0;
1251     }
1252   }
1253   if (c) {
1254     emit_ldst(is_store, 1, pair[0], SP, SSP_CALLEE_REGS + ofs);
1255     ofs += 8;
1256   }
1257   assert(ofs <= SSP_CALLER_REGS);
1258 }
1259
1260 // Save registers before function call
1261 static void save_regs(u_int reglist)
1262 {
1263   reglist &= CALLER_SAVE_REGS; // only save the caller-save registers
1264   save_load_regs_all(1, reglist);
1265 }
1266
1267 // Restore registers after function call
1268 static void restore_regs(u_int reglist)
1269 {
1270   reglist &= CALLER_SAVE_REGS;
1271   save_load_regs_all(0, reglist);
1272 }
1273
1274 /* Stubs/epilogue */
1275
1276 static void literal_pool(int n)
1277 {
1278   (void)literals;
1279 }
1280
1281 static void literal_pool_jumpover(int n)
1282 {
1283 }
1284
1285 // parsed by get_pointer, find_extjump_insn
1286 static void emit_extjump2(u_char *addr, u_int target, void *linker)
1287 {
1288   assert(((addr[3]&0xfc)==0x14) || ((addr[3]&0xff)==0x54)); // b or b.cond
1289
1290   emit_movz(target & 0xffff, 0);
1291   emit_movk_lsl16(target >> 16, 0);
1292
1293   // addr is in the current recompiled block (max 256k)
1294   // offset shouldn't exceed +/-1MB
1295   emit_adr(addr, 1);
1296   emit_far_jump(linker);
1297 }
1298
1299 static void check_extjump2(void *src)
1300 {
1301   u_int *ptr = src;
1302   assert((ptr[0] & 0xffe0001f) == 0x52800000); // movz r0, #val
1303   (void)ptr;
1304 }
1305
1306 // put rt_val into rt, potentially making use of rs with value rs_val
1307 static void emit_movimm_from(u_int rs_val, u_int rs, u_int rt_val, u_int rt)
1308 {
1309   int diff = rt_val - rs_val;
1310   if ((-4096 < diff && diff < 4096)
1311       || (-16777216 < diff && diff < 16777216 && !(diff & 0xfff)))
1312     emit_addimm(rs, diff, rt);
1313   else if (rt_val == ~rs_val)
1314     emit_not(rs, rt);
1315   else if (is_rotated_mask(rs_val ^ rt_val))
1316     emit_xorimm(rs, rs_val ^ rt_val, rt);
1317   else
1318     emit_movimm(rt_val, rt);
1319 }
1320
1321 // return 1 if the above function can do it's job cheaply
1322 static int is_similar_value(u_int v1, u_int v2)
1323 {
1324   int diff = v1 - v2;
1325   return (-4096 < diff && diff < 4096)
1326     || (-16777216 < diff && diff < 16777216 && !(diff & 0xfff))
1327     || v1 == ~v2
1328     || is_rotated_mask(v1 ^ v2);
1329 }
1330
1331 // trashes r2
1332 static void pass_args64(u_int a0, u_int a1)
1333 {
1334   if(a0==1&&a1==0) {
1335     // must swap
1336     emit_mov64(a0,2); emit_mov64(a1,1); emit_mov64(2,0);
1337   }
1338   else if(a0!=0&&a1==0) {
1339     emit_mov64(a1,1);
1340     if (a0>=0) emit_mov64(a0,0);
1341   }
1342   else {
1343     if(a0>=0&&a0!=0) emit_mov64(a0,0);
1344     if(a1>=0&&a1!=1) emit_mov64(a1,1);
1345   }
1346 }
1347
1348 static void loadstore_extend(enum stub_type type, u_int rs, u_int rt)
1349 {
1350   switch(type) {
1351     case LOADB_STUB:  emit_sbfm(rs, 7, rt); break;
1352     case LOADBU_STUB:
1353     case STOREB_STUB: emit_ubfm(rs, 7, rt); break;
1354     case LOADH_STUB:  emit_sbfm(rs, 15, rt); break;
1355     case LOADHU_STUB:
1356     case STOREH_STUB: emit_ubfm(rs, 15, rt); break;
1357     case LOADW_STUB:  
1358     case STOREW_STUB: if (rs != rt) emit_mov(rs, rt); break;
1359     default:          assert(0);
1360   }
1361 }
1362
1363 #include "pcsxmem.h"
1364 //#include "pcsxmem_inline.c"
1365
1366 static void do_readstub(int n)
1367 {
1368   assem_debug("do_readstub %x\n",start+stubs[n].a*4);
1369   set_jump_target(stubs[n].addr, out);
1370   enum stub_type type = stubs[n].type;
1371   int i = stubs[n].a;
1372   int rs = stubs[n].b;
1373   const struct regstat *i_regs = (void *)stubs[n].c;
1374   u_int reglist = stubs[n].e;
1375   const signed char *i_regmap = i_regs->regmap;
1376   int rt;
1377   if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) {
1378     rt=get_reg(i_regmap,FTEMP);
1379   }else{
1380     rt=get_reg(i_regmap,rt1[i]);
1381   }
1382   assert(rs>=0);
1383   int r,temp=-1,temp2=HOST_TEMPREG,regs_saved=0;
1384   void *restore_jump = NULL, *handler_jump = NULL;
1385   reglist|=(1<<rs);
1386   for (r = 0; r < HOST_CCREG; r++) {
1387     if (r != EXCLUDE_REG && ((1 << r) & reglist) == 0) {
1388       temp = r;
1389       break;
1390     }
1391   }
1392   if(rt>=0&&rt1[i]!=0)
1393     reglist&=~(1<<rt);
1394   if(temp==-1) {
1395     save_regs(reglist);
1396     regs_saved=1;
1397     temp=(rs==0)?2:0;
1398   }
1399   if((regs_saved||(reglist&2)==0)&&temp!=1&&rs!=1)
1400     temp2=1;
1401   emit_readdword(&mem_rtab,temp);
1402   emit_shrimm(rs,12,temp2);
1403   emit_readdword_dualindexedx8(temp,temp2,temp2);
1404   emit_adds64(temp2,temp2,temp2);
1405   handler_jump=out;
1406   emit_jc(0);
1407   if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
1408     switch(type) {
1409       case LOADB_STUB:  emit_ldrsb_dualindexed(temp2,rs,rt); break;
1410       case LOADBU_STUB: emit_ldrb_dualindexed(temp2,rs,rt); break;
1411       case LOADH_STUB:  emit_ldrsh_dualindexed(temp2,rs,rt); break;
1412       case LOADHU_STUB: emit_ldrh_dualindexed(temp2,rs,rt); break;
1413       case LOADW_STUB:  emit_ldr_dualindexed(temp2,rs,rt); break;
1414       default:          assert(0);
1415     }
1416   }
1417   if(regs_saved) {
1418     restore_jump=out;
1419     emit_jmp(0); // jump to reg restore
1420   }
1421   else
1422     emit_jmp(stubs[n].retaddr); // return address
1423   set_jump_target(handler_jump, out);
1424
1425   if(!regs_saved)
1426     save_regs(reglist);
1427   void *handler=NULL;
1428   if(type==LOADB_STUB||type==LOADBU_STUB)
1429     handler=jump_handler_read8;
1430   if(type==LOADH_STUB||type==LOADHU_STUB)
1431     handler=jump_handler_read16;
1432   if(type==LOADW_STUB)
1433     handler=jump_handler_read32;
1434   assert(handler);
1435   pass_args64(rs,temp2);
1436   int cc=get_reg(i_regmap,CCREG);
1437   if(cc<0)
1438     emit_loadreg(CCREG,2);
1439   emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n].d),2);
1440   emit_far_call(handler);
1441   // (no cycle reload after read)
1442   if(itype[i]==C1LS||itype[i]==C2LS||(rt>=0&&rt1[i]!=0)) {
1443     loadstore_extend(type,0,rt);
1444   }
1445   if(restore_jump)
1446     set_jump_target(restore_jump, out);
1447   restore_regs(reglist);
1448   emit_jmp(stubs[n].retaddr);
1449 }
1450
1451 static void inline_readstub(enum stub_type type, int i, u_int addr,
1452   const signed char regmap[], int target, int adj, u_int reglist)
1453 {
1454   int rs=get_reg(regmap,target);
1455   int rt=get_reg(regmap,target);
1456   if(rs<0) rs=get_reg(regmap,-1);
1457   assert(rs>=0);
1458   u_int is_dynamic=0;
1459   uintptr_t host_addr = 0;
1460   void *handler;
1461   int cc=get_reg(regmap,CCREG);
1462   //if(pcsx_direct_read(type,addr,CLOCK_ADJUST(adj),cc,target?rs:-1,rt))
1463   //  return;
1464   handler = get_direct_memhandler(mem_rtab, addr, type, &host_addr);
1465   if (handler == NULL) {
1466     if(rt<0||rt1[i]==0)
1467       return;
1468     if (addr != host_addr) {
1469       if (host_addr >= 0x100000000ull)
1470         abort(); // ROREG not implemented
1471       emit_movimm_from(addr, rs, host_addr, rs);
1472     }
1473     switch(type) {
1474       case LOADB_STUB:  emit_movsbl_indexed(0,rs,rt); break;
1475       case LOADBU_STUB: emit_movzbl_indexed(0,rs,rt); break;
1476       case LOADH_STUB:  emit_movswl_indexed(0,rs,rt); break;
1477       case LOADHU_STUB: emit_movzwl_indexed(0,rs,rt); break;
1478       case LOADW_STUB:  emit_readword_indexed(0,rs,rt); break;
1479       default:          assert(0);
1480     }
1481     return;
1482   }
1483   is_dynamic=pcsxmem_is_handler_dynamic(addr);
1484   if(is_dynamic) {
1485     if(type==LOADB_STUB||type==LOADBU_STUB)
1486       handler=jump_handler_read8;
1487     if(type==LOADH_STUB||type==LOADHU_STUB)
1488       handler=jump_handler_read16;
1489     if(type==LOADW_STUB)
1490       handler=jump_handler_read32;
1491   }
1492
1493   // call a memhandler
1494   if(rt>=0&&rt1[i]!=0)
1495     reglist&=~(1<<rt);
1496   save_regs(reglist);
1497   if(target==0)
1498     emit_movimm(addr,0);
1499   else if(rs!=0)
1500     emit_mov(rs,0);
1501   if(cc<0)
1502     emit_loadreg(CCREG,2);
1503   emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj),2);
1504   if(is_dynamic) {
1505     uintptr_t l1 = ((uintptr_t *)mem_rtab)[addr>>12] << 1;
1506     emit_adrp((void *)l1, 1);
1507     emit_addimm64(1, l1 & 0xfff, 1);
1508   }
1509   else
1510     emit_far_call(do_memhandler_pre);
1511
1512   emit_far_call(handler);
1513
1514   // (no cycle reload after read)
1515   if(rt>=0&&rt1[i]!=0)
1516     loadstore_extend(type, 0, rt);
1517   restore_regs(reglist);
1518 }
1519
1520 static void do_writestub(int n)
1521 {
1522   assem_debug("do_writestub %x\n",start+stubs[n].a*4);
1523   set_jump_target(stubs[n].addr, out);
1524   enum stub_type type=stubs[n].type;
1525   int i=stubs[n].a;
1526   int rs=stubs[n].b;
1527   struct regstat *i_regs=(struct regstat *)stubs[n].c;
1528   u_int reglist=stubs[n].e;
1529   signed char *i_regmap=i_regs->regmap;
1530   int rt,r;
1531   if(itype[i]==C1LS||itype[i]==C2LS) {
1532     rt=get_reg(i_regmap,r=FTEMP);
1533   }else{
1534     rt=get_reg(i_regmap,r=rs2[i]);
1535   }
1536   assert(rs>=0);
1537   assert(rt>=0);
1538   int rtmp,temp=-1,temp2,regs_saved=0;
1539   void *restore_jump = NULL, *handler_jump = NULL;
1540   int reglist2=reglist|(1<<rs)|(1<<rt);
1541   for (rtmp = 0; rtmp < HOST_CCREG; rtmp++) {
1542     if (rtmp != EXCLUDE_REG && ((1 << rtmp) & reglist) == 0) {
1543       temp = rtmp;
1544       break;
1545     }
1546   }
1547   if(temp==-1) {
1548     save_regs(reglist);
1549     regs_saved=1;
1550     for(rtmp=0;rtmp<=3;rtmp++)
1551       if(rtmp!=rs&&rtmp!=rt)
1552         {temp=rtmp;break;}
1553   }
1554   if((regs_saved||(reglist2&8)==0)&&temp!=3&&rs!=3&&rt!=3)
1555     temp2=3;
1556   else {
1557     host_tempreg_acquire();
1558     temp2=HOST_TEMPREG;
1559   }
1560   emit_readdword(&mem_wtab,temp);
1561   emit_shrimm(rs,12,temp2);
1562   emit_readdword_dualindexedx8(temp,temp2,temp2);
1563   emit_adds64(temp2,temp2,temp2);
1564   handler_jump=out;
1565   emit_jc(0);
1566   switch(type) {
1567     case STOREB_STUB: emit_strb_dualindexed(temp2,rs,rt); break;
1568     case STOREH_STUB: emit_strh_dualindexed(temp2,rs,rt); break;
1569     case STOREW_STUB: emit_str_dualindexed(temp2,rs,rt); break;
1570     default:          assert(0);
1571   }
1572   if(regs_saved) {
1573     restore_jump=out;
1574     emit_jmp(0); // jump to reg restore
1575   }
1576   else
1577     emit_jmp(stubs[n].retaddr); // return address (invcode check)
1578   set_jump_target(handler_jump, out);
1579
1580   // TODO FIXME: regalloc should prefer callee-saved regs
1581   if(!regs_saved)
1582     save_regs(reglist);
1583   void *handler=NULL;
1584   switch(type) {
1585     case STOREB_STUB: handler=jump_handler_write8; break;
1586     case STOREH_STUB: handler=jump_handler_write16; break;
1587     case STOREW_STUB: handler=jump_handler_write32; break;
1588     default:          assert(0);
1589   }
1590   assert(handler);
1591   pass_args(rs,rt);
1592   if(temp2!=3) {
1593     emit_mov64(temp2,3);
1594     host_tempreg_release();
1595   }
1596   int cc=get_reg(i_regmap,CCREG);
1597   if(cc<0)
1598     emit_loadreg(CCREG,2);
1599   emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n].d),2);
1600   // returns new cycle_count
1601   emit_far_call(handler);
1602   emit_addimm(0,-CLOCK_ADJUST((int)stubs[n].d),cc<0?2:cc);
1603   if(cc<0)
1604     emit_storereg(CCREG,2);
1605   if(restore_jump)
1606     set_jump_target(restore_jump, out);
1607   restore_regs(reglist);
1608   emit_jmp(stubs[n].retaddr);
1609 }
1610
1611 static void inline_writestub(enum stub_type type, int i, u_int addr,
1612   const signed char regmap[], int target, int adj, u_int reglist)
1613 {
1614   int rs = get_reg(regmap,-1);
1615   int rt = get_reg(regmap,target);
1616   assert(rs >= 0);
1617   assert(rt >= 0);
1618   uintptr_t host_addr = 0;
1619   void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr);
1620   if (handler == NULL) {
1621     if (addr != host_addr) {
1622       if (host_addr >= 0x100000000ull)
1623         abort(); // ROREG not implemented
1624       emit_movimm_from(addr, rs, host_addr, rs);
1625     }
1626     switch (type) {
1627       case STOREB_STUB: emit_writebyte_indexed(rt, 0, rs); break;
1628       case STOREH_STUB: emit_writehword_indexed(rt, 0, rs); break;
1629       case STOREW_STUB: emit_writeword_indexed(rt, 0, rs); break;
1630       default:          assert(0);
1631     }
1632     return;
1633   }
1634
1635   // call a memhandler
1636   save_regs(reglist);
1637   emit_writeword(rs, &address); // some handlers still need it
1638   loadstore_extend(type, rt, 0);
1639   int cc, cc_use;
1640   cc = cc_use = get_reg(regmap, CCREG);
1641   if (cc < 0)
1642     emit_loadreg(CCREG, (cc_use = 2));
1643   emit_addimm(cc_use, CLOCK_ADJUST(adj), 2);
1644
1645   emit_far_call(do_memhandler_pre);
1646   emit_far_call(handler);
1647   emit_far_call(do_memhandler_post);
1648   emit_addimm(0, -CLOCK_ADJUST(adj), cc_use);
1649   if (cc < 0)
1650     emit_storereg(CCREG, cc_use);
1651   restore_regs(reglist);
1652 }
1653
1654 static int verify_code_arm64(const void *source, const void *copy, u_int size)
1655 {
1656   int ret = memcmp(source, copy, size);
1657   //printf("%s %p,%#x = %d\n", __func__, source, size, ret);
1658   return ret;
1659 }
1660
1661 // this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr
1662 static void do_dirty_stub_base(u_int vaddr)
1663 {
1664   assert(slen <= MAXBLOCK);
1665   emit_loadlp_ofs(0, 0); // ldr x1, source
1666   emit_loadlp_ofs(0, 1); // ldr x2, copy
1667   emit_movz(slen*4, 2);
1668   emit_far_call(verify_code_arm64);
1669   void *jmp = out;
1670   emit_cbz(0, 0);
1671   emit_movz(vaddr & 0xffff, 0);
1672   emit_movk_lsl16(vaddr >> 16, 0);
1673   emit_far_call(get_addr);
1674   emit_jmpreg(0);
1675   set_jump_target(jmp, out);
1676 }
1677
1678 static void assert_dirty_stub(const u_int *ptr)
1679 {
1680   assert((ptr[0] & 0xff00001f) == 0x58000000); // ldr x0, source
1681   assert((ptr[1] & 0xff00001f) == 0x58000001); // ldr x1, copy
1682   assert((ptr[2] & 0xffe0001f) == 0x52800002); // movz w2, #slen*4
1683   assert( ptr[8]               == 0xd61f0000); // br x0
1684 }
1685
1686 static void set_loadlp(u_int *loadl, void *lit)
1687 {
1688   uintptr_t ofs = (u_char *)lit - (u_char *)loadl;
1689   assert((*loadl & ~0x1f) == 0x58000000);
1690   assert((ofs & 3) == 0);
1691   assert(ofs < 0x100000);
1692   *loadl |= (ofs >> 2) << 5;
1693 }
1694
1695 static void do_dirty_stub_emit_literals(u_int *loadlps)
1696 {
1697   set_loadlp(&loadlps[0], out);
1698   output_w64((uintptr_t)source);
1699   set_loadlp(&loadlps[1], out);
1700   output_w64((uintptr_t)copy);
1701 }
1702
1703 static void *do_dirty_stub(int i)
1704 {
1705   assem_debug("do_dirty_stub %x\n",start+i*4);
1706   u_int *loadlps = (void *)out;
1707   do_dirty_stub_base(start + i*4);
1708   void *entry = out;
1709   load_regs_entry(i);
1710   if (entry == out)
1711     entry = instr_addr[i];
1712   emit_jmp(instr_addr[i]);
1713   do_dirty_stub_emit_literals(loadlps);
1714   return entry;
1715 }
1716
1717 static void do_dirty_stub_ds(void)
1718 {
1719   u_int *loadlps = (void *)out;
1720   do_dirty_stub_base(start + 1);
1721   void *lit_jumpover = out;
1722   emit_jmp(out + 8*2);
1723   do_dirty_stub_emit_literals(loadlps);
1724   set_jump_target(lit_jumpover, out);
1725 }
1726
1727 static uint64_t get_from_ldr_literal(const u_int *i)
1728 {
1729   signed int ofs;
1730   assert((i[0] & 0xff000000) == 0x58000000);
1731   ofs = i[0] << 8;
1732   ofs >>= 5+8;
1733   return *(uint64_t *)(i + ofs);
1734 }
1735
1736 static uint64_t get_from_movz(const u_int *i)
1737 {
1738   assert((i[0] & 0x7fe00000) == 0x52800000);
1739   return (i[0] >> 5) & 0xffff;
1740 }
1741
1742 // Find the "clean" entry point from a "dirty" entry point
1743 // by skipping past the call to verify_code
1744 static void *get_clean_addr(u_int *addr)
1745 {
1746   assert_dirty_stub(addr);
1747   return addr + 9;
1748 }
1749
1750 static int verify_dirty(const u_int *ptr)
1751 {
1752   const void *source, *copy;
1753   u_int len;
1754   assert_dirty_stub(ptr);
1755   source = (void *)get_from_ldr_literal(&ptr[0]); // ldr x1, source
1756   copy   = (void *)get_from_ldr_literal(&ptr[1]); // ldr x1, copy
1757   len = get_from_movz(&ptr[2]);                   // movz w3, #slen*4
1758   return !memcmp(source, copy, len);
1759 }
1760
1761 static int isclean(void *addr)
1762 {
1763   const u_int *ptr = addr;
1764   if ((*ptr >> 24) == 0x58) { // the only place ldr (literal) is used
1765     assert_dirty_stub(ptr);
1766     return 0;
1767   }
1768   return 1;
1769 }
1770
1771 // get source that block at addr was compiled from (host pointers)
1772 static void get_bounds(void *addr, u_char **start, u_char **end)
1773 {
1774   const u_int *ptr = addr;
1775   assert_dirty_stub(ptr);
1776   *start = (u_char *)get_from_ldr_literal(&ptr[0]); // ldr x1, source
1777   *end = *start + get_from_movz(&ptr[2]);           // movz w3, #slen*4
1778 }
1779
1780 /* Special assem */
1781
1782 static void c2op_prologue(u_int op, int i, const struct regstat *i_regs, u_int reglist)
1783 {
1784   save_load_regs_all(1, reglist);
1785   cop2_call_stall_check(op, i, i_regs, 0);
1786 #ifdef PCNT
1787   emit_movimm(op, 0);
1788   emit_far_call(pcnt_gte_start);
1789 #endif
1790   // pointer to cop2 regs
1791   emit_addimm64(FP, (u_char *)&psxRegs.CP2D.r[0] - (u_char *)&dynarec_local, 0);
1792 }
1793
1794 static void c2op_epilogue(u_int op,u_int reglist)
1795 {
1796 #ifdef PCNT
1797   emit_movimm(op, 0);
1798   emit_far_call(pcnt_gte_end);
1799 #endif
1800   save_load_regs_all(0, reglist);
1801 }
1802
1803 static void c2op_assemble(int i, const struct regstat *i_regs)
1804 {
1805   u_int c2op=source[i]&0x3f;
1806   u_int hr,reglist_full=0,reglist;
1807   int need_flags,need_ir;
1808   for(hr=0;hr<HOST_REGS;hr++) {
1809     if(i_regs->regmap[hr]>=0) reglist_full|=1<<hr;
1810   }
1811   reglist=reglist_full&CALLER_SAVE_REGS;
1812
1813   if (gte_handlers[c2op]!=NULL) {
1814     need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
1815     need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
1816     assem_debug("gte op %08x, unneeded %016lx, need_flags %d, need_ir %d\n",
1817       source[i],gte_unneeded[i+1],need_flags,need_ir);
1818     if(HACK_ENABLED(NDHACK_GTE_NO_FLAGS))
1819       need_flags=0;
1820     //int shift = (source[i] >> 19) & 1;
1821     //int lm = (source[i] >> 10) & 1;
1822     switch(c2op) {
1823       default:
1824         (void)need_ir;
1825         c2op_prologue(c2op, i, i_regs, reglist);
1826         emit_movimm(source[i],1); // opcode
1827         emit_writeword(1,&psxRegs.code);
1828         emit_far_call(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]);
1829         break;
1830     }
1831     c2op_epilogue(c2op,reglist);
1832   }
1833 }
1834
1835 static void c2op_ctc2_31_assemble(signed char sl, signed char temp)
1836 {
1837   //value = value & 0x7ffff000;
1838   //if (value & 0x7f87e000) value |= 0x80000000;
1839   emit_andimm(sl, 0x7fffe000, temp);
1840   emit_testimm(temp, 0xff87ffff);
1841   emit_andimm(sl, 0x7ffff000, temp);
1842   host_tempreg_acquire();
1843   emit_orimm(temp, 0x80000000, HOST_TEMPREG);
1844   emit_cmovne_reg(HOST_TEMPREG, temp);
1845   host_tempreg_release();
1846   assert(0); // testing needed
1847 }
1848
1849 static void do_mfc2_31_one(u_int copr,signed char temp)
1850 {
1851   emit_readshword(&reg_cop2d[copr],temp);
1852   emit_bicsar_imm(temp,31,temp);
1853   emit_cmpimm(temp,0xf80);
1854   emit_csinvle_reg(temp,WZR,temp); // if (temp > 0xf80) temp = ~0;
1855   emit_andimm(temp,0xf80,temp);
1856 }
1857
1858 static void c2op_mfc2_29_assemble(signed char tl, signed char temp)
1859 {
1860   if (temp < 0) {
1861     host_tempreg_acquire();
1862     temp = HOST_TEMPREG;
1863   }
1864   do_mfc2_31_one(9,temp);
1865   emit_shrimm(temp,7,tl);
1866   do_mfc2_31_one(10,temp);
1867   emit_orrshr_imm(temp,2,tl);
1868   do_mfc2_31_one(11,temp);
1869   emit_orrshl_imm(temp,3,tl);
1870   emit_writeword(tl,&reg_cop2d[29]);
1871
1872   if (temp == HOST_TEMPREG)
1873     host_tempreg_release();
1874 }
1875
1876 static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
1877 {
1878   //  case 0x18: MULT
1879   //  case 0x19: MULTU
1880   //  case 0x1A: DIV
1881   //  case 0x1B: DIVU
1882   if(rs1[i]&&rs2[i])
1883   {
1884     switch(opcode2[i])
1885     {
1886     case 0x18: // MULT
1887     case 0x19: // MULTU
1888       {
1889         signed char m1=get_reg(i_regs->regmap,rs1[i]);
1890         signed char m2=get_reg(i_regs->regmap,rs2[i]);
1891         signed char hi=get_reg(i_regs->regmap,HIREG);
1892         signed char lo=get_reg(i_regs->regmap,LOREG);
1893         assert(m1>=0);
1894         assert(m2>=0);
1895         assert(hi>=0);
1896         assert(lo>=0);
1897
1898         if(opcode2[i]==0x18) // MULT
1899           emit_smull(m1,m2,hi);
1900         else                 // MULTU
1901           emit_umull(m1,m2,hi);
1902
1903         emit_mov(hi,lo);
1904         emit_shrimm64(hi,32,hi);
1905         break;
1906       }
1907     case 0x1A: // DIV
1908     case 0x1B: // DIVU
1909       {
1910         signed char numerator=get_reg(i_regs->regmap,rs1[i]);
1911         signed char denominator=get_reg(i_regs->regmap,rs2[i]);
1912         signed char quotient=get_reg(i_regs->regmap,LOREG);
1913         signed char remainder=get_reg(i_regs->regmap,HIREG);
1914         assert(numerator>=0);
1915         assert(denominator>=0);
1916         assert(quotient>=0);
1917         assert(remainder>=0);
1918
1919         if (opcode2[i] == 0x1A) // DIV
1920           emit_sdiv(numerator,denominator,quotient);
1921         else                    // DIVU
1922           emit_udiv(numerator,denominator,quotient);
1923         emit_msub(quotient,denominator,numerator,remainder);
1924
1925         // div 0 quotient (remainder is already correct)
1926         host_tempreg_acquire();
1927         if (opcode2[i] == 0x1A) // DIV
1928           emit_sub_asrimm(0,numerator,31,HOST_TEMPREG);
1929         else
1930           emit_movimm(~0,HOST_TEMPREG);
1931         emit_test(denominator,denominator);
1932         emit_cmoveq_reg(HOST_TEMPREG,quotient);
1933         host_tempreg_release();
1934         break;
1935       }
1936     default:
1937       assert(0);
1938     }
1939   }
1940   else
1941   {
1942     signed char hr=get_reg(i_regs->regmap,HIREG);
1943     signed char lr=get_reg(i_regs->regmap,LOREG);
1944     if ((opcode2[i]==0x1A || opcode2[i]==0x1B) && rs2[i]==0) // div 0
1945     {
1946       if (rs1[i]) {
1947         signed char numerator = get_reg(i_regs->regmap, rs1[i]);
1948         assert(numerator >= 0);
1949         if (hr >= 0)
1950           emit_mov(numerator,hr);
1951         if (lr >= 0) {
1952           if (opcode2[i] == 0x1A) // DIV
1953             emit_sub_asrimm(0,numerator,31,lr);
1954           else
1955             emit_movimm(~0,lr);
1956         }
1957       }
1958       else {
1959         if (hr >= 0) emit_zeroreg(hr);
1960         if (lr >= 0) emit_movimm(~0,lr);
1961       }
1962     }
1963     else
1964     {
1965       // Multiply by zero is zero.
1966       if (hr >= 0) emit_zeroreg(hr);
1967       if (lr >= 0) emit_zeroreg(lr);
1968     }
1969   }
1970 }
1971 #define multdiv_assemble multdiv_assemble_arm64
1972
1973 static void do_jump_vaddr(u_int rs)
1974 {
1975   if (rs != 0)
1976     emit_mov(rs, 0);
1977   emit_far_call(get_addr_ht);
1978   emit_jmpreg(0);
1979 }
1980
1981 static void do_preload_rhash(u_int r) {
1982   // Don't need this for ARM.  On x86, this puts the value 0xf8 into the
1983   // register.  On ARM the hash can be done with a single instruction (below)
1984 }
1985
1986 static void do_preload_rhtbl(u_int ht) {
1987   emit_addimm64(FP, (u_char *)&mini_ht - (u_char *)&dynarec_local, ht);
1988 }
1989
1990 static void do_rhash(u_int rs,u_int rh) {
1991   emit_andimm(rs, 0xf8, rh);
1992 }
1993
1994 static void do_miniht_load(int ht, u_int rh) {
1995   emit_add64(ht, rh, ht);
1996   emit_ldst(0, 0, rh, ht, 0);
1997 }
1998
1999 static void do_miniht_jump(u_int rs, u_int rh, u_int ht) {
2000   emit_cmp(rh, rs);
2001   void *jaddr = out;
2002   emit_jeq(0);
2003   do_jump_vaddr(rs);
2004
2005   set_jump_target(jaddr, out);
2006   assem_debug("ldr %s,[%s,#8]\n",regname64[ht], regname64[ht]);
2007   output_w32(0xf9400000 | imm12_rn_rd(8 >> 3, ht, ht));
2008   emit_jmpreg(ht);
2009 }
2010
2011 // parsed by set_jump_target?
2012 static void do_miniht_insert(u_int return_address,u_int rt,int temp) {
2013   emit_movz_lsl16((return_address>>16)&0xffff,rt);
2014   emit_movk(return_address&0xffff,rt);
2015   add_to_linker(out,return_address,1);
2016   emit_adr(out,temp);
2017   emit_writedword(temp,&mini_ht[(return_address&0xFF)>>3][1]);
2018   emit_writeword(rt,&mini_ht[(return_address&0xFF)>>3][0]);
2019 }
2020
2021 static void clear_cache_arm64(char *start, char *end)
2022 {
2023   // Don't rely on GCC's __clear_cache implementation, as it caches
2024   // icache/dcache cache line sizes, that can vary between cores on
2025   // big.LITTLE architectures.
2026   uint64_t addr, ctr_el0;
2027   static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff;
2028   size_t isize, dsize;
2029
2030   __asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
2031   isize = 4 << ((ctr_el0 >> 0) & 0xf);
2032   dsize = 4 << ((ctr_el0 >> 16) & 0xf);
2033
2034   // use the global minimum cache line size
2035   icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize;
2036   dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize;
2037
2038   /* If CTR_EL0.IDC is enabled, Data cache clean to the Point of Unification is
2039      not required for instruction to data coherence.  */
2040   if ((ctr_el0 & (1 << 28)) == 0x0) {
2041     addr = (uint64_t)start & ~(uint64_t)(dsize - 1);
2042     for (; addr < (uint64_t)end; addr += dsize)
2043       // use "civac" instead of "cvau", as this is the suggested workaround for
2044       // Cortex-A53 errata 819472, 826319, 827319 and 824069.
2045       __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
2046   }
2047   __asm__ volatile("dsb ish" : : : "memory");
2048
2049   /* If CTR_EL0.DIC is enabled, Instruction cache cleaning to the Point of
2050      Unification is not required for instruction to data coherence.  */
2051   if ((ctr_el0 & (1 << 29)) == 0x0) {
2052     addr = (uint64_t)start & ~(uint64_t)(isize - 1);
2053     for (; addr < (uint64_t)end; addr += isize)
2054       __asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory");
2055
2056     __asm__ volatile("dsb ish" : : : "memory");
2057   }
2058
2059   __asm__ volatile("isb" : : : "memory");
2060 }
2061
2062 // CPU-architecture-specific initialization
2063 static void arch_init(void)
2064 {
2065   uintptr_t diff = (u_char *)&ndrc->tramp.f - (u_char *)&ndrc->tramp.ops;
2066   struct tramp_insns *ops = ndrc->tramp.ops;
2067   size_t i;
2068   assert(!(diff & 3));
2069   start_tcache_write(ops, (u_char *)ops + sizeof(ndrc->tramp.ops));
2070   for (i = 0; i < ARRAY_SIZE(ndrc->tramp.ops); i++) {
2071     ops[i].ldr = 0x58000000 | imm19_rt(diff >> 2, 17); // ldr x17, [=val]
2072     ops[i].br  = 0xd61f0000 | rm_rn_rd(0, 17, 0);      // br x17
2073   }
2074   end_tcache_write(ops, (u_char *)ops + sizeof(ndrc->tramp.ops));
2075 }
2076
2077 // vim:shiftwidth=2:expandtab