drc: some more general cleanup
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / assem_arm64.c
CommitLineData
be516ebe 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)
26u_char *translation_cache;
27#else
28u_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
be516ebe 35static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
36
37//void indirect_jump_indexed();
38//void indirect_jump();
39void do_interrupt();
40//void jump_vaddr_r0();
41
42void * const jump_vaddr_reg[32];
43
44/* Linker */
45
46static 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
53static 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
63static 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
72static void *get_clean_addr(void *addr)
73{
74 assert(0);
75 return NULL;
76}
77
78static 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
86static 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)
93static void get_bounds(void *addr, u_char **start, u_char **end)
94{
95 assert(0);
96}
97
98// Allocate a specific ARM register.
99static 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
120static 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
130static 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
be516ebe 137static void output_w32(u_int word)
138{
139 *((u_int *)out) = word;
140 out += 4;
141}
142
687b4580 143static 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
be516ebe 150static 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
687b4580 158static 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
be516ebe 164static 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
687b4580 171static 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"
be516ebe 180static 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
193static 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
206static void emit_mov(u_int rs, u_int rt)
207{
687b4580 208 assem_debug("mov %s,%s\n", regname[rt], regname[rs]);
209 output_w32(0x2a0003e0 | rm_rd(rs, rt));
be516ebe 210}
211
212static void emit_movs(u_int rs, u_int rt)
213{
687b4580 214 assem_debug("movs %s,%s\n", regname[rt], regname[rs]);
215 output_w32(0x31000000 | imm12_rn_rd(0, rs, rt));
be516ebe 216}
217
687b4580 218static void emit_add(u_int rs1, u_int rs2, u_int rt)
be516ebe 219{
687b4580 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));
be516ebe 222}
223
224static 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
230static 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
236static 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
687b4580 242static void emit_sub(u_int rs1, u_int rs2, u_int rt)
be516ebe 243{
687b4580 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));
be516ebe 246}
247
248static 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
254static void emit_zeroreg(u_int rt)
255{
256 assem_debug("mov %s,#0\n",regname[rt]);
257 assert(0);
258}
259
be516ebe 260static void emit_movimm(u_int imm, u_int rt)
261{
687b4580 262 assem_debug("mov %s,#%#x\n", regname[rt], imm);
be516ebe 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
687b4580 273static 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
be516ebe 284static void emit_loadreg(u_int r, u_int hr)
285{
286 assert(r < 64);
287 if (r == 0)
288 emit_zeroreg(hr);
289 else {
7c3a5182 290 void *addr = &psxRegs.GPR.r[r];
be516ebe 291 switch (r) {
7c3a5182 292 //case HIREG: addr = &hi; break;
293 //case LOREG: addr = &lo; break;
be516ebe 294 case CCREG: addr = &cycle_count; break;
295 case CSREG: addr = &Status; break;
296 case INVCP: addr = &invc_ptr; break;
7c3a5182 297 default: assert(r < 34); break;
be516ebe 298 }
687b4580 299 emit_readword(addr, hr);
be516ebe 300 }
301}
302
687b4580 303static 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
314static void emit_storereg(u_int r, u_int hr)
be516ebe 315{
316 assert(r < 64);
7c3a5182 317 void *addr = &psxRegs.GPR.r[r];
be516ebe 318 switch (r) {
7c3a5182 319 //case HIREG: addr = &hi; break;
320 //case LOREG: addr = &lo; break;
be516ebe 321 case CCREG: addr = &cycle_count; break;
7c3a5182 322 default: assert(r < 34); break;
be516ebe 323 }
687b4580 324 emit_writeword(hr, addr);
be516ebe 325}
326
327static 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
333static void emit_testimm(u_int rs,int imm)
334{
687b4580 335 assem_debug("tst %s,#%#x\n", regname[rs], imm);
be516ebe 336 assert(0);
337}
338
339static void emit_testeqimm(u_int rs,int imm)
340{
341 assem_debug("tsteq %s,$%d\n",regname[rs],imm);
342 assert(0);
343}
344
345static 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
351static 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
357static 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
363static 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
369static 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
378static 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
387static 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
393static 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
399static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
400{
687b4580 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);
be516ebe 411}
412
413static void emit_addimm_and_set_flags(int imm, u_int rt)
414{
415 assert(0);
416}
417
418static void emit_addimm_no_flags(u_int imm,u_int rt)
419{
420 emit_addimm(rt,imm,rt);
421}
422
be516ebe 423static void emit_adcimm(u_int rs,int imm,u_int rt)
424{
687b4580 425 assem_debug("adc %s,%s,#%#x\n",regname[rt],regname[rs],imm);
be516ebe 426 assert(0);
427}
428
429static void emit_rscimm(u_int rs,int imm,u_int rt)
430{
687b4580 431 assem_debug("rsc %s,%s,#%#x\n",regname[rt],regname[rs],imm);
be516ebe 432 assert(0);
433}
434
435static void emit_addimm64_32(u_int rsh,u_int rsl,int imm,u_int rth,u_int rtl)
436{
437 assert(0);
438}
439
440static void emit_andimm(u_int rs,int imm,u_int rt)
441{
442 assert(0);
443}
444
445static void emit_orimm(u_int rs,int imm,u_int rt)
446{
447 assert(0);
448}
449
450static void emit_xorimm(u_int rs,int imm,u_int rt)
451{
452 assert(0);
453}
454
455static 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
463static 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
471static 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
479static 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
487static 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
495static 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
503static 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
509static 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
517static 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
526static 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
535static 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
544static 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
553static void emit_cmpimm(u_int rs,int imm)
554{
555 assert(0);
556}
557
558static void emit_cmovne_imm(int imm,u_int rt)
559{
687b4580 560 assem_debug("movne %s,#%#x\n",regname[rt],imm);
be516ebe 561 assert(0);
562}
563
564static void emit_cmovl_imm(int imm,u_int rt)
565{
687b4580 566 assem_debug("movlt %s,#%#x\n",regname[rt],imm);
be516ebe 567 assert(0);
568}
569
570static void emit_cmovb_imm(int imm,u_int rt)
571{
687b4580 572 assem_debug("movcc %s,#%#x\n",regname[rt],imm);
be516ebe 573 assert(0);
574}
575
576static void emit_cmovs_imm(int imm,u_int rt)
577{
687b4580 578 assem_debug("movmi %s,#%#x\n",regname[rt],imm);
be516ebe 579 assert(0);
580}
581
582static 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
588static 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
594static 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
600static 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
608static 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
616static 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
622static 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
630static void emit_set_nz32(u_int rs, u_int rt)
631{
632 //assem_debug("set_nz32\n");
633 assert(0);
634}
635
636static 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
645static 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
be516ebe 654static void emit_call(const void *a_)
655{
687b4580 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);
be516ebe 663}
664
687b4580 665#pragma GCC diagnostic ignored "-Wunused-variable"
be516ebe 666static 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
673static 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
7c3a5182 680static void emit_jeq(const void *a)
be516ebe 681{
7c3a5182 682 assem_debug("beq %p\n",a);
be516ebe 683 assert(0);
684}
685
7c3a5182 686static void emit_js(const void *a)
be516ebe 687{
7c3a5182 688 assem_debug("bmi %p\n",a);
be516ebe 689 assert(0);
690}
691
7c3a5182 692static void emit_jns(const void *a)
be516ebe 693{
7c3a5182 694 assem_debug("bpl %p\n",a);
be516ebe 695 assert(0);
696}
697
7c3a5182 698static void emit_jl(const void *a)
be516ebe 699{
7c3a5182 700 assem_debug("blt %p\n",a);
be516ebe 701 assert(0);
702}
703
7c3a5182 704static void emit_jge(const void *a)
be516ebe 705{
7c3a5182 706 assem_debug("bge %p\n",a);
be516ebe 707 assert(0);
708}
709
7c3a5182 710static void emit_jno(const void *a)
be516ebe 711{
7c3a5182 712 assem_debug("bvc %p\n",a);
be516ebe 713 assert(0);
714}
715
7c3a5182 716static void emit_jc(const void *a)
be516ebe 717{
7c3a5182 718 assem_debug("bcs %p\n",a);
be516ebe 719 assert(0);
720}
721
7c3a5182 722static void emit_jcc(const void *a)
be516ebe 723{
7c3a5182 724 assem_debug("bcc %p\n", a);
be516ebe 725 assert(0);
726}
727
728static void emit_callreg(u_int r)
729{
730 assert(r < 31);
731 assem_debug("blx %s\n", regname[r]);
732 assert(0);
733}
734
735static void emit_jmpreg(u_int r)
736{
737 assem_debug("mov pc,%s\n",regname[r]);
738 assert(0);
739}
740
741static void emit_retreg(u_int r)
742{
743 assem_debug("ret %s\n", r == LR ? "" : regname[r]);
744 output_w32(0xd65f0000 | rm_rn_rd(0, r, 0));
745}
746
747static void emit_ret(void)
748{
749 emit_retreg(LR);
750}
751
752static void emit_readword_indexed(int offset, u_int rs, u_int rt)
753{
754 assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
755 assert(0);
756}
757
be516ebe 758static void emit_movsbl_indexed(int offset, u_int rs, u_int rt)
759{
760 assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
761 assert(0);
762}
763
764static void emit_movswl_indexed(int offset, u_int rs, u_int rt)
765{
766 assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
767 assert(0);
768}
769
770static void emit_movzbl_indexed(int offset, u_int rs, u_int rt)
771{
772 assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
773 assert(0);
774}
775
776static void emit_movzwl_indexed(int offset, u_int rs, u_int rt)
777{
778 assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
779 assert(0);
780}
781
be516ebe 782static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
783{
687b4580 784 assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
785 if (!(offset & 3) && offset <= 16380)
786 output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt));
787 else
788 assert(0);
be516ebe 789}
790
791static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
792{
687b4580 793 assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
794 if (!(offset & 1) && offset <= 8190)
795 output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt));
796 else
797 assert(0);
be516ebe 798}
799
800static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
801{
687b4580 802 assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
803 if ((u_int)offset < 4096)
804 output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt));
805 else
806 assert(0);
be516ebe 807}
808
809static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
810{
811 assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
812 assert(rs1<16);
813 assert(rs2<16);
814 assert(hi<16);
815 assert(lo<16);
816 assert(0);
817}
818
819static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
820{
821 assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
822 assert(rs1<16);
823 assert(rs2<16);
824 assert(hi<16);
825 assert(lo<16);
826 assert(0);
827}
828
829static void emit_clz(u_int rs,u_int rt)
830{
831 assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
832 assert(0);
833}
834
835// Load 2 immediates optimizing for small code size
836static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
837{
838 assert(0);
839}
840
841// Conditionally select one of two immediates, optimizing for small code size
842// This will only be called if HAVE_CMOV_IMM is defined
843static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
844{
845 assert(0);
846}
847
848// special case for checking invalid_code
849static void emit_cmpmem_indexedsr12_reg(int base,u_int r,int imm)
850{
851 assert(imm<128&&imm>=0);
852 assert(r>=0&&r<16);
853 assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
854 assert(0);
855}
856
857// Used to preload hash table entries
858static unused void emit_prefetchreg(u_int r)
859{
860 assem_debug("pld %s\n",regname[r]);
861 assert(0);
862}
863
864// Special case for mini_ht
865static void emit_ldreq_indexed(u_int rs, u_int offset, u_int rt)
866{
867 assert(offset<4096);
687b4580 868 assem_debug("ldreq %s,[%s, #%#x]\n",regname[rt],regname[rs],offset);
be516ebe 869 assert(0);
870}
871
872static void emit_orrne_imm(u_int rs,int imm,u_int rt)
873{
687b4580 874 assem_debug("orrne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
be516ebe 875 assert(0);
876}
877
878static void emit_andne_imm(u_int rs,int imm,u_int rt)
879{
687b4580 880 assem_debug("andne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
be516ebe 881 assert(0);
882}
883
884static unused void emit_addpl_imm(u_int rs,int imm,u_int rt)
885{
687b4580 886 assem_debug("addpl %s,%s,#%#x\n",regname[rt],regname[rs],imm);
be516ebe 887 assert(0);
888}
889
687b4580 890static void emit_ldst(int is_st, int is64, u_int rt, u_int rn, u_int ofs)
be516ebe 891{
687b4580 892 u_int op = 0xb9000000;
893 const char *ldst = is_st ? "st" : "ld";
894 char rp = is64 ? 'x' : 'w';
895 assem_debug("%sr %c%d,[x%d,#%#x]\n", ldst, rp, rt, rn, ofs);
896 is64 = is64 ? 1 : 0;
897 assert((ofs & ((1 << (2+is64)) - 1)) == 0);
898 ofs = (ofs >> (2+is64));
899 assert(ofs <= 0xfff);
900 if (!is_st) op |= 0x00400000;
901 if (is64) op |= 0x40000000;
902 output_w32(op | (ofs << 15) | imm12_rn_rd(ofs, rn, rt));
be516ebe 903}
904
687b4580 905static void emit_ldstp(int is_st, int is64, u_int rt1, u_int rt2, u_int rn, int ofs)
be516ebe 906{
687b4580 907 u_int op = 0x29000000;
908 const char *ldst = is_st ? "st" : "ld";
909 char rp = is64 ? 'x' : 'w';
910 assem_debug("%sp %c%d,%c%d,[x%d,#%#x]\n", ldst, rp, rt1, rp, rt2, rn, ofs);
911 is64 = is64 ? 1 : 0;
912 assert((ofs & ((1 << (2+is64)) - 1)) == 0);
913 ofs = (ofs >> (2+is64));
914 assert(-64 <= ofs && ofs <= 63);
915 ofs &= 0x7f;
916 if (!is_st) op |= 0x00400000;
917 if (is64) op |= 0x80000000;
918 output_w32(op | (ofs << 15) | rm_rn_rd(rt2, rn, rt1));
919}
920
921static void save_load_regs_all(int is_store, u_int reglist)
922{
923 int ofs = 0, c = 0;
924 u_int r, pair[2];
925 for (r = 0; reglist; r++, reglist >>= 1) {
926 if (reglist & 1)
927 pair[c++] = r;
928 if (c == 2) {
929 emit_ldstp(is_store, 1, pair[0], pair[1], SP, SSP_CALLEE_REGS + ofs);
930 ofs += 8 * 2;
931 c = 0;
932 }
933 }
934 if (c) {
935 emit_ldst(is_store, 1, pair[0], SP, SSP_CALLEE_REGS + ofs);
936 ofs += 8;
937 }
938 assert(ofs <= SSP_CALLER_REGS);
be516ebe 939}
940
941// Save registers before function call
942static void save_regs(u_int reglist)
943{
944 reglist &= CALLER_SAVE_REGS; // only save the caller-save registers
687b4580 945 save_load_regs_all(1, reglist);
be516ebe 946}
947
948// Restore registers after function call
949static void restore_regs(u_int reglist)
950{
951 reglist &= CALLER_SAVE_REGS;
687b4580 952 save_load_regs_all(0, reglist);
be516ebe 953}
954
955/* Stubs/epilogue */
956
957static void literal_pool(int n)
958{
959 (void)literals;
960}
961
962static void literal_pool_jumpover(int n)
963{
964}
965
966static void emit_extjump2(u_char *addr, int target, void *linker)
967{
968 assert(0);
969}
970
971static void emit_extjump(void *addr, int target)
972{
973 emit_extjump2(addr, target, dyna_linker);
974}
975
976static void emit_extjump_ds(void *addr, int target)
977{
978 emit_extjump2(addr, target, dyna_linker_ds);
979}
980
981// put rt_val into rt, potentially making use of rs with value rs_val
687b4580 982static void emit_movimm_from(u_int rs_val, u_int rs, uintptr_t rt_val, u_int rt)
be516ebe 983{
687b4580 984 intptr_t diff = rt_val - rs_val;
985 if (-4096 < diff && diff < 4096)
986 emit_addimm(rs, diff, rt);
987 else
988 // TODO: for inline_writestub, etc
989 assert(0);
be516ebe 990}
991
992// return 1 if above function can do it's job cheaply
687b4580 993static int is_similar_value(u_int v1, u_int v2)
be516ebe 994{
687b4580 995 int diff = v1 - v2;
996 return -4096 < diff && diff < 4096;
be516ebe 997}
998
999//#include "pcsxmem.h"
1000//#include "pcsxmem_inline.c"
1001
1002static void do_readstub(int n)
1003{
1004 assem_debug("do_readstub %x\n",start+stubs[n].a*4);
1005 assert(0);
1006}
1007
1008static void inline_readstub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1009{
1010 assert(0);
1011}
1012
1013static void do_writestub(int n)
1014{
1015 assem_debug("do_writestub %x\n",start+stubs[n].a*4);
1016 assert(0);
1017}
1018
1019static void inline_writestub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1020{
687b4580 1021 int rs = get_reg(regmap,-1);
1022 int rt = get_reg(regmap,target);
1023 assert(rs >= 0);
1024 assert(rt >= 0);
1025 uintptr_t host_addr = 0;
1026 void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr);
1027 if (handler == NULL) {
1028 if (addr != host_addr)
1029 emit_movimm_from(addr, rs, host_addr, rs);
1030 switch(type) {
1031 case STOREB_STUB: emit_writebyte_indexed(rt, 0, rs); break;
1032 case STOREH_STUB: emit_writehword_indexed(rt, 0, rs); break;
1033 case STOREW_STUB: emit_writeword_indexed(rt, 0, rs); break;
1034 default: assert(0);
1035 }
1036 return;
1037 }
1038
1039 // call a memhandler
1040 save_regs(reglist);
1041 //pass_args(rs, rt);
1042 int cc = get_reg(regmap, CCREG);
1043 assert(cc >= 0);
1044 emit_addimm(cc, CLOCK_ADJUST(adj+1), 2);
1045 //emit_movimm((uintptr_t)handler, 3);
1046 // returns new cycle_count
1047
1048 emit_readword(&last_count, HOST_TEMPREG);
1049 emit_writeword(rs, &address); // some handlers still need it
1050 emit_add(2, HOST_TEMPREG, 2);
1051 emit_writeword(2, &Count);
1052 emit_mov(1, 0);
1053 emit_call(handler);
1054 emit_readword(&next_interupt, 0);
1055 emit_readword(&Count, 1);
1056 emit_writeword(0, &last_count);
1057 emit_sub(1, 0, cc);
1058
1059 emit_addimm(cc,-CLOCK_ADJUST(adj+1),cc);
1060 restore_regs(reglist);
be516ebe 1061}
1062
1063static void do_unalignedwritestub(int n)
1064{
1065 assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
1066 assert(0);
1067}
1068
1069static void do_invstub(int n)
1070{
1071 assert(0);
1072}
1073
1074void *do_dirty_stub(int i)
1075{
1076 assem_debug("do_dirty_stub %x\n",start+i*4);
1077 // Careful about the code output here, verify_dirty needs to parse it.
1078 assert(0);
1079 load_regs_entry(i);
1080 return NULL;
1081}
1082
1083static void do_dirty_stub_ds()
1084{
1085 // Careful about the code output here, verify_dirty needs to parse it.
1086 assert(0);
1087}
1088
1089/* Special assem */
1090
1091#define shift_assemble shift_assemble_arm64
1092
1093static void shift_assemble_arm64(int i,struct regstat *i_regs)
1094{
1095 assert(0);
1096}
1097#define loadlr_assemble loadlr_assemble_arm64
1098
1099static void loadlr_assemble_arm64(int i,struct regstat *i_regs)
1100{
1101 assert(0);
1102}
1103
1104static void c2op_assemble(int i,struct regstat *i_regs)
1105{
1106 assert(0);
1107}
1108
1109static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
1110{
1111 assert(0);
1112}
1113#define multdiv_assemble multdiv_assemble_arm64
1114
1115static void do_preload_rhash(u_int r) {
1116 // Don't need this for ARM. On x86, this puts the value 0xf8 into the
1117 // register. On ARM the hash can be done with a single instruction (below)
1118}
1119
1120static void do_preload_rhtbl(u_int ht) {
1121 emit_addimm(FP, (u_char *)&mini_ht - (u_char *)&dynarec_local, ht);
1122}
1123
1124static void do_rhash(u_int rs,u_int rh) {
1125 emit_andimm(rs, 0xf8, rh);
1126}
1127
1128static void do_miniht_load(int ht,u_int rh) {
1129 assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
1130 assert(0);
1131}
1132
1133static void do_miniht_jump(u_int rs,u_int rh,int ht) {
1134 emit_cmp(rh,rs);
1135 emit_ldreq_indexed(ht,4,15);
1136 //emit_jmp(jump_vaddr_reg[rs]);
1137 assert(0);
1138}
1139
1140static void do_miniht_insert(u_int return_address,u_int rt,int temp) {
1141 assert(0);
1142}
1143
1144static void mark_clear_cache(void *target)
1145{
1146 u_long offset = (u_char *)target - translation_cache;
1147 u_int mask = 1u << ((offset >> 12) & 31);
1148 if (!(needs_clear_cache[offset >> 17] & mask)) {
1149 char *start = (char *)((u_long)target & ~4095ul);
1150 start_tcache_write(start, start + 4096);
1151 needs_clear_cache[offset >> 17] |= mask;
1152 }
1153}
1154
1155// Clearing the cache is rather slow on ARM Linux, so mark the areas
1156// that need to be cleared, and then only clear these areas once.
1157static void do_clear_cache()
1158{
1159 int i,j;
1160 for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
1161 {
1162 u_int bitmap=needs_clear_cache[i];
1163 if(bitmap) {
1164 u_char *start, *end;
1165 for(j=0;j<32;j++)
1166 {
1167 if(bitmap&(1<<j)) {
1168 start=translation_cache+i*131072+j*4096;
1169 end=start+4095;
1170 j++;
1171 while(j<32) {
1172 if(bitmap&(1<<j)) {
1173 end+=4096;
1174 j++;
1175 }else{
1176 end_tcache_write(start, end);
1177 break;
1178 }
1179 }
1180 }
1181 }
1182 needs_clear_cache[i]=0;
1183 }
1184 }
1185}
1186
1187// CPU-architecture-specific initialization
1188static void arch_init() {
1189}
1190
1191// vim:shiftwidth=2:expandtab