32x: add missing pprof call for draw
[picodrive.git] / cpu / sh2 / compiler.c
CommitLineData
e898de13 1/*
2 * vim:shiftwidth=2:expandtab
44e6452e 3 *
4 * notes:
5 * - tcache, block descriptor, link buffer overflows result in sh2_translate()
6 * failure, followed by full tcache invalidation for that region
9bb5d91c 7 * - jumps between blocks are tracked for SMC handling (in block_links[]),
8 * except jumps between different tcaches
9 *
10 * implemented:
11 * - static register allocation
12 * - remaining register caching and tracking in temporaries
13 * - block-local branch linking
14 * - block linking (except between tcaches)
15 *
16 * TODO:
17 * - proper SMC handling
18 * - constant propagation
19 * - stack caching?
20 * - bug fixing
e898de13 21 */
f0d7b1fa 22#include <stddef.h>
679af8a3 23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
41397701 26
f4bb5d6b 27#include "../../pico/pico_int.h"
679af8a3 28#include "sh2.h"
29#include "compiler.h"
30#include "../drc/cmn.h"
31
8796b7ee 32// debug stuff {
e898de13 33#ifndef DRC_DEBUG
34#define DRC_DEBUG 0
35#endif
36
553c3eaa 37#if DRC_DEBUG
f4bb5d6b 38#define dbg(l,...) { \
39 if ((l) & DRC_DEBUG) \
40 elprintf(EL_STATUS, ##__VA_ARGS__); \
41}
42
e898de13 43#include "mame/sh2dasm.h"
44#include <platform/linux/host_dasm.h>
45static int insns_compiled, hash_collisions, host_insn_count;
553c3eaa 46#define COUNT_OP \
47 host_insn_count++
48#else // !DRC_DEBUG
49#define COUNT_OP
50#define dbg(...)
e898de13 51#endif
553c3eaa 52
e898de13 53#if (DRC_DEBUG & 2)
f4bb5d6b 54static u8 *tcache_dsm_ptrs[3];
e898de13 55static char sh2dasm_buff[64];
f4bb5d6b 56#define do_host_disasm(tcid) \
57 host_dasm(tcache_dsm_ptrs[tcid], tcache_ptr - tcache_dsm_ptrs[tcid]); \
58 tcache_dsm_ptrs[tcid] = tcache_ptr
59#else
60#define do_host_disasm(x)
e898de13 61#endif
e05b81fc 62
63#if (DRC_DEBUG & 4)
64static void REGPARM(3) *sh2_drc_announce_entry(void *block, SH2 *sh2, u32 sr)
65{
66 if (block != NULL)
67 dbg(4, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
68 sh2->pc, block, (signed int)sr >> 12);
69 return block;
70}
71#endif
8796b7ee 72// } debug
e898de13 73
679af8a3 74#define BLOCK_CYCLE_LIMIT 100
f4bb5d6b 75#define MAX_BLOCK_SIZE (BLOCK_CYCLE_LIMIT * 6 * 6)
44e6452e 76#define TCACHE_BUFFERS 3
f4bb5d6b 77
78// we have 3 translation cache buffers, split from one drc/cmn buffer.
79// BIOS shares tcache with data array because it's only used for init
80// and can be discarded early
8796b7ee 81// XXX: need to tune sizes
44e6452e 82static const int tcache_sizes[TCACHE_BUFFERS] = {
f4bb5d6b 83 DRC_TCACHE_SIZE * 6 / 8, // ROM, DRAM
84 DRC_TCACHE_SIZE / 8, // BIOS, data array in master sh2
85 DRC_TCACHE_SIZE / 8, // ... slave
86};
679af8a3 87
44e6452e 88static u8 *tcache_bases[TCACHE_BUFFERS];
89static u8 *tcache_ptrs[TCACHE_BUFFERS];
f4bb5d6b 90
91// ptr for code emiters
92static u8 *tcache_ptr;
e898de13 93
44e6452e 94typedef struct block_desc_ {
95 u32 addr; // SH2 PC address
96 u32 end_addr; // TODO rm?
97 void *tcache_ptr; // translated block for above PC
98 struct block_desc_ *next; // next block with the same PC hash
99#if (DRC_DEBUG & 1)
100 int refcount;
101#endif
102} block_desc;
103
104typedef struct block_link_ {
105 u32 target_pc;
106 void *jump;
107// struct block_link_ *next;
108} block_link;
109
110static const int block_max_counts[TCACHE_BUFFERS] = {
111 4*1024,
112 256,
113 256,
114};
115static block_desc *block_tables[TCACHE_BUFFERS];
116static block_link *block_links[TCACHE_BUFFERS];
117static int block_counts[TCACHE_BUFFERS];
118static int block_link_counts[TCACHE_BUFFERS];
119
c18edb34 120// host register tracking
121enum {
122 HR_FREE,
123 HR_CACHED, // 'val' has sh2_reg_e
124 HR_CACHED_DIRTY,
125 HR_CONST, // 'val' has constant
126 HR_TEMP, // reg used for temp storage
127};
128
129typedef struct {
130 u8 reg;
131 u8 type;
132 u16 stamp; // kind of a timestamp
133 u32 val;
134} temp_reg_t;
135
80599a42 136// note: reg_temp[] must have at least the amount of
3863edbd 137// registers used by handlers in worst case (currently 4)
65c75cb0 138#ifdef ARM
139#include "../drc/emit_arm.c"
140
141static const int reg_map_g2h[] = {
8b4f38f4 142 4, 5, 6, 7,
143 8, -1, -1, -1,
c18edb34 144 -1, -1, -1, -1,
8b4f38f4 145 -1, -1, -1, 9,
146 -1, -1, -1, 10,
c18edb34 147 -1, -1, -1, -1,
148};
149
150static temp_reg_t reg_temp[] = {
151 { 0, },
152 { 1, },
153 { 12, },
154 { 14, },
155 { 2, },
156 { 3, },
65c75cb0 157};
158
e05b81fc 159#elif defined(__i386__)
e898de13 160#include "../drc/emit_x86.c"
161
65c75cb0 162static const int reg_map_g2h[] = {
8b4f38f4 163 xSI,-1, -1, -1,
c18edb34 164 -1, -1, -1, -1,
165 -1, -1, -1, -1,
166 -1, -1, -1, -1,
8b4f38f4 167 -1, -1, -1, xDI,
c18edb34 168 -1, -1, -1, -1,
169};
170
3863edbd 171// ax, cx, dx are usually temporaries by convention
c18edb34 172static temp_reg_t reg_temp[] = {
173 { xAX, },
3863edbd 174 { xBX, },
c18edb34 175 { xCX, },
176 { xDX, },
65c75cb0 177};
178
e05b81fc 179#else
180#error unsupported arch
65c75cb0 181#endif
182
80599a42 183#define T 0x00000001
184#define S 0x00000002
185#define I 0x000000f0
186#define Q 0x00000100
187#define M 0x00000200
18b94127 188#define T_save 0x00000800
80599a42 189
e05b81fc 190#define I_SHIFT 4
f0d7b1fa 191#define Q_SHIFT 8
192#define M_SHIFT 9
193
f4bb5d6b 194// ROM hash table
679af8a3 195#define MAX_HASH_ENTRIES 1024
196#define HASH_MASK (MAX_HASH_ENTRIES - 1)
f4bb5d6b 197static void **hash_table;
679af8a3 198
18b94127 199#define HASH_FUNC(hash_tab, addr) \
200 ((block_desc **)(hash_tab))[(addr) & HASH_MASK]
201
e05b81fc 202static void REGPARM(1) (*sh2_drc_entry)(SH2 *sh2);
203static void (*sh2_drc_dispatcher)(void);
204static void (*sh2_drc_exit)(void);
205static void (*sh2_drc_test_irq)(void);
206static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
207static void REGPARM(2) (*sh2_drc_write8_slot)(u32 a, u32 d);
208static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
209static void REGPARM(2) (*sh2_drc_write16_slot)(u32 a, u32 d);
679af8a3 210
553c3eaa 211extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
679af8a3 212
f4bb5d6b 213static void flush_tcache(int tcid)
214{
553c3eaa 215 dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
f4bb5d6b 216 tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
217 block_counts[tcid], block_max_counts[tcid]);
218
219 block_counts[tcid] = 0;
220 tcache_ptrs[tcid] = tcache_bases[tcid];
221 if (tcid == 0) { // ROM, RAM
222 memset(hash_table, 0, sizeof(hash_table[0]) * MAX_HASH_ENTRIES);
223 memset(Pico32xMem->drcblk_ram, 0, sizeof(Pico32xMem->drcblk_ram));
224 }
225 else
226 memset(Pico32xMem->drcblk_da[tcid - 1], 0, sizeof(Pico32xMem->drcblk_da[0]));
227#if (DRC_DEBUG & 2)
228 tcache_dsm_ptrs[tcid] = tcache_bases[tcid];
229#endif
230}
231
44e6452e 232// add block links (tracked branches)
233static int dr_add_block_link(u32 target_pc, void *jump, int tcache_id)
234{
235 block_link *bl = block_links[tcache_id];
236 int cnt = block_link_counts[tcache_id];
237
238 if (cnt >= block_max_counts[tcache_id] * 2) {
239 printf("bl overflow for tcache %d\n", tcache_id);
240 return -1;
241 }
242
243 bl[cnt].target_pc = target_pc;
244 bl[cnt].jump = jump;
245 block_link_counts[tcache_id]++;
246
247 return 0;
248}
249
679af8a3 250static void *dr_find_block(block_desc *tab, u32 addr)
251{
252 for (tab = tab->next; tab != NULL; tab = tab->next)
253 if (tab->addr == addr)
254 break;
255
256 if (tab != NULL)
257 return tab->tcache_ptr;
258
259 printf("block miss for %08x\n", addr);
260 return NULL;
261}
262
f4bb5d6b 263static block_desc *dr_add_block(u32 addr, int tcache_id, int *blk_id)
679af8a3 264{
f4bb5d6b 265 int *bcount = &block_counts[tcache_id];
679af8a3 266 block_desc *bd;
267
44e6452e 268 if (*bcount >= block_max_counts[tcache_id]) {
269 printf("bd overflow for tcache %d\n", tcache_id);
f4bb5d6b 270 return NULL;
44e6452e 271 }
679af8a3 272
f4bb5d6b 273 bd = &block_tables[tcache_id][*bcount];
679af8a3 274 bd->addr = addr;
275 bd->tcache_ptr = tcache_ptr;
f4bb5d6b 276 *blk_id = *bcount;
277 (*bcount)++;
679af8a3 278
18b94127 279 if ((addr & 0xc6000000) == 0x02000000) { // ROM
280 bd->next = HASH_FUNC(hash_table, addr);
281 HASH_FUNC(hash_table, addr) = bd;
282#if (DRC_DEBUG & 1)
283 if (bd->next != NULL) {
284 printf(" hash collision with %08x\n", bd->next->addr);
285 hash_collisions++;
286 }
287#endif
288 }
289
679af8a3 290 return bd;
291}
292
44e6452e 293#define ADD_TO_ARRAY(array, count, item, failcode) \
294 array[count++] = item; \
295 if (count >= ARRAY_SIZE(array)) { \
296 printf("warning: " #array " overflow\n"); \
297 failcode; \
298 }
299
18b94127 300int find_in_array(u32 *array, size_t size, u32 what)
301{
302 size_t i;
303 for (i = 0; i < size; i++)
304 if (what == array[i])
305 return i;
306
307 return -1;
308}
679af8a3 309
310// ---------------------------------------------------------------
311
c18edb34 312// register chache
313static u16 rcache_counter;
314
315static temp_reg_t *rcache_evict(void)
41397701 316{
c18edb34 317 // evict reg with oldest stamp
318 int i, oldest = -1;
319 u16 min_stamp = (u16)-1;
320
321 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
322 if (reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY)
323 if (reg_temp[i].stamp <= min_stamp) {
324 min_stamp = reg_temp[i].stamp;
325 oldest = i;
326 }
327 }
328
329 if (oldest == -1) {
80599a42 330 printf("no registers to evict, aborting\n");
c18edb34 331 exit(1);
332 }
333
334 i = oldest;
335 if (reg_temp[i].type == HR_CACHED_DIRTY) {
336 // writeback
337 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
338 }
339
340 return &reg_temp[i];
679af8a3 341}
342
c18edb34 343typedef enum {
344 RC_GR_READ,
345 RC_GR_WRITE,
346 RC_GR_RMW,
347} rc_gr_mode;
348
80599a42 349// note: must not be called when doing conditional code
c18edb34 350static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
679af8a3 351{
c18edb34 352 temp_reg_t *tr;
353 int i;
354
355 // maybe already statically mapped?
356 i = reg_map_g2h[r];
357 if (i != -1)
358 return i;
679af8a3 359
c18edb34 360 rcache_counter++;
361
362 // maybe already cached?
363 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
364 if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
365 reg_temp[i].val == r)
366 {
367 reg_temp[i].stamp = rcache_counter;
368 if (mode != RC_GR_READ)
369 reg_temp[i].type = HR_CACHED_DIRTY;
370 return reg_temp[i].reg;
371 }
679af8a3 372 }
373
c18edb34 374 // use any free reg
375 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
376 if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
377 tr = &reg_temp[i];
378 goto do_alloc;
379 }
380 }
381
382 tr = rcache_evict();
383
384do_alloc:
385 if (mode != RC_GR_WRITE)
386 emith_ctx_read(tr->reg, r * 4);
679af8a3 387
c18edb34 388 tr->type = mode != RC_GR_READ ? HR_CACHED_DIRTY : HR_CACHED;
389 tr->val = r;
390 tr->stamp = rcache_counter;
391 return tr->reg;
679af8a3 392}
393
c18edb34 394static int rcache_get_tmp(void)
679af8a3 395{
c18edb34 396 temp_reg_t *tr;
397 int i;
398
399 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
400 if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
401 tr = &reg_temp[i];
402 goto do_alloc;
403 }
404
405 tr = rcache_evict();
406
407do_alloc:
408 tr->type = HR_TEMP;
409 return tr->reg;
410}
411
80599a42 412static int rcache_get_arg_id(int arg)
413{
414 int i, r = 0;
415 host_arg2reg(r, arg);
416
417 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
418 if (reg_temp[i].reg == r)
419 break;
420
421 if (i == ARRAY_SIZE(reg_temp))
422 // let's just say it's untracked arg reg
423 return r;
424
425 if (reg_temp[i].type == HR_CACHED_DIRTY) {
426 // writeback
427 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
428 }
429 else if (reg_temp[i].type == HR_TEMP) {
430 printf("arg %d reg %d already used, aborting\n", arg, r);
431 exit(1);
432 }
433
434 return i;
435}
436
437// get a reg to be used as function arg
438// it's assumed that regs are cleaned before call
439static int rcache_get_tmp_arg(int arg)
440{
441 int id = rcache_get_arg_id(arg);
442 reg_temp[id].type = HR_TEMP;
443
444 return reg_temp[id].reg;
445}
446
447// same but caches reg. RC_GR_READ only.
448static int rcache_get_reg_arg(int arg, sh2_reg_e r)
449{
450 int i, srcr, dstr, dstid;
451
452 dstid = rcache_get_arg_id(arg);
453 dstr = reg_temp[dstid].reg;
454
455 // maybe already statically mapped?
456 srcr = reg_map_g2h[r];
457 if (srcr != -1)
458 goto do_cache;
459
460 // maybe already cached?
461 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
462 if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
463 reg_temp[i].val == r)
464 {
465 srcr = reg_temp[i].reg;
466 goto do_cache;
467 }
468 }
469
470 // must read
471 srcr = dstr;
472 emith_ctx_read(srcr, r * 4);
473
474do_cache:
475 if (srcr != dstr)
476 emith_move_r_r(dstr, srcr);
477
478 reg_temp[dstid].stamp = ++rcache_counter;
479 reg_temp[dstid].type = HR_CACHED;
480 reg_temp[dstid].val = r;
481 return dstr;
482}
483
c18edb34 484static void rcache_free_tmp(int hr)
485{
486 int i;
487 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
488 if (reg_temp[i].reg == hr)
489 break;
490
80599a42 491 if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP) {
c18edb34 492 printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
80599a42 493 return;
494 }
495
496 reg_temp[i].type = HR_FREE;
c18edb34 497}
498
80599a42 499static void rcache_clean(void)
c18edb34 500{
501 int i;
80599a42 502 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
c18edb34 503 if (reg_temp[i].type == HR_CACHED_DIRTY) {
504 // writeback
505 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
80599a42 506 reg_temp[i].type = HR_CACHED;
c18edb34 507 }
80599a42 508}
509
510static void rcache_invalidate(void)
511{
512 int i;
513 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
c18edb34 514 reg_temp[i].type = HR_FREE;
c18edb34 515 rcache_counter = 0;
516}
517
80599a42 518static void rcache_flush(void)
519{
520 rcache_clean();
521 rcache_invalidate();
522}
523
c18edb34 524// ---------------------------------------------------------------
525
526static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
527{
52d759c3 528 // TODO: propagate this constant
c18edb34 529 int hr = rcache_get_reg(dst, RC_GR_WRITE);
530 emith_move_r_imm(hr, imm);
531}
532
533static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
534{
535 int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
536 int hr_s = rcache_get_reg(src, RC_GR_READ);
537
538 emith_move_r_r(hr_d, hr_s);
679af8a3 539}
540
52d759c3 541// T must be clear, and comparison done just before this
542static void emit_or_t_if_eq(int srr)
543{
544 EMITH_SJMP_START(DCOND_NE);
545 emith_or_r_imm_c(DCOND_EQ, srr, T);
546 EMITH_SJMP_END(DCOND_NE);
547}
548
80599a42 549// arguments must be ready
550// reg cache must be clean before call
551static int emit_memhandler_read(int size)
679af8a3 552{
b081408f 553 int arg0, arg1;
554 host_arg2reg(arg0, 0);
555
556 // must writeback cycles for poll detection stuff
557 if (reg_map_g2h[SHR_SR] != -1)
558 emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
559 arg1 = rcache_get_tmp_arg(1);
560 emith_move_r_r(arg1, CONTEXT_REG);
561
562#if 1
563 if (Pico.rom == (void *)0x02000000 && Pico32xMem->sdram == (void *)0x06000000) {
564 int tmp = rcache_get_tmp();
565 emith_and_r_r_imm(tmp, arg0, 0xfb000000);
566 emith_cmp_r_imm(tmp, 0x02000000);
567 switch (size) {
568 case 0: // 8
569 EMITH_SJMP3_START(DCOND_NE);
570 emith_eor_r_imm_c(DCOND_EQ, arg0, 1);
571 emith_read8_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
572 EMITH_SJMP3_MID(DCOND_NE);
573 emith_call_cond(DCOND_NE, p32x_sh2_read8);
574 EMITH_SJMP3_END();
575 break;
576 case 1: // 16
577 EMITH_SJMP3_START(DCOND_NE);
578 emith_read16_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
579 EMITH_SJMP3_MID(DCOND_NE);
580 emith_call_cond(DCOND_NE, p32x_sh2_read16);
581 EMITH_SJMP3_END();
582 break;
583 case 2: // 32
584 EMITH_SJMP3_START(DCOND_NE);
585 emith_read_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
586 emith_ror_c(DCOND_EQ, arg0, arg0, 16);
587 EMITH_SJMP3_MID(DCOND_NE);
588 emith_call_cond(DCOND_NE, p32x_sh2_read32);
589 EMITH_SJMP3_END();
590 break;
591 }
592 }
593 else
594#endif
595 {
596 switch (size) {
597 case 0: // 8
598 emith_call(p32x_sh2_read8);
599 break;
600 case 1: // 16
601 emith_call(p32x_sh2_read16);
602 break;
603 case 2: // 32
604 emith_call(p32x_sh2_read32);
605 break;
606 }
679af8a3 607 }
80599a42 608 rcache_invalidate();
609 // assuming arg0 and retval reg matches
610 return rcache_get_tmp_arg(0);
611}
679af8a3 612
e05b81fc 613static void emit_memhandler_write(int size, u32 pc, int delay)
80599a42 614{
615 int ctxr;
616 host_arg2reg(ctxr, 2);
80599a42 617 switch (size) {
618 case 0: // 8
e05b81fc 619 // XXX: consider inlining sh2_drc_write8
620 if (delay) {
621 emith_call(sh2_drc_write8_slot);
622 } else {
623 emit_move_r_imm32(SHR_PC, pc);
624 rcache_clean();
625 emith_call(sh2_drc_write8);
626 }
80599a42 627 break;
628 case 1: // 16
e05b81fc 629 if (delay) {
630 emith_call(sh2_drc_write16_slot);
631 } else {
632 emit_move_r_imm32(SHR_PC, pc);
633 rcache_clean();
634 emith_call(sh2_drc_write16);
635 }
80599a42 636 break;
637 case 2: // 32
e05b81fc 638 emith_move_r_r(ctxr, CONTEXT_REG);
80599a42 639 emith_call(p32x_sh2_write32);
640 break;
641 }
642 rcache_invalidate();
679af8a3 643}
80599a42 644
52d759c3 645// @(Rx,Ry)
646static int emit_indirect_indexed_read(int rx, int ry, int size)
647{
648 int a0, t;
649 rcache_clean();
650 a0 = rcache_get_reg_arg(0, rx);
651 t = rcache_get_reg(ry, RC_GR_READ);
652 emith_add_r_r(a0, t);
653 return emit_memhandler_read(size);
654}
655
f0d7b1fa 656// read @Rn, @rm
657static void emit_indirect_read_double(u32 *rnr, u32 *rmr, int rn, int rm, int size)
658{
659 int tmp;
660
661 rcache_clean();
662 rcache_get_reg_arg(0, rn);
663 tmp = emit_memhandler_read(size);
664 emith_ctx_write(tmp, offsetof(SH2, drc_tmp));
665 rcache_free_tmp(tmp);
666 tmp = rcache_get_reg(rn, RC_GR_RMW);
667 emith_add_r_imm(tmp, 1 << size);
668
669 rcache_clean();
670 rcache_get_reg_arg(0, rm);
671 *rmr = emit_memhandler_read(size);
672 *rnr = rcache_get_tmp();
673 emith_ctx_read(*rnr, offsetof(SH2, drc_tmp));
674 tmp = rcache_get_reg(rm, RC_GR_RMW);
675 emith_add_r_imm(tmp, 1 << size);
676}
677
8796b7ee 678static void emit_do_static_regs(int is_write, int tmpr)
f0d7b1fa 679{
8796b7ee 680 int i, r, count;
681
682 for (i = 0; i < ARRAY_SIZE(reg_map_g2h); i++) {
683 r = reg_map_g2h[i];
684 if (r == -1)
685 continue;
686
687 for (count = 1; i < ARRAY_SIZE(reg_map_g2h) - 1; i++, r++) {
688 if (reg_map_g2h[i + 1] != r + 1)
689 break;
690 count++;
691 }
692
693 if (count > 1) {
694 // i, r point to last item
695 if (is_write)
696 emith_ctx_write_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
697 else
698 emith_ctx_read_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
699 } else {
700 if (is_write)
701 emith_ctx_write(r, i * 4);
702 else
703 emith_ctx_read(r, i * 4);
704 }
f0d7b1fa 705 }
706}
707
e05b81fc 708static void emit_block_entry(void)
f0d7b1fa 709{
e05b81fc 710 int arg0, arg1, arg2;
8796b7ee 711
e05b81fc 712 host_arg2reg(arg0, 0);
713 host_arg2reg(arg1, 1);
714 host_arg2reg(arg2, 2);
8796b7ee 715
e05b81fc 716#if (DRC_DEBUG & 4)
717 emith_move_r_r(arg1, CONTEXT_REG);
718 emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
719 emith_call(sh2_drc_announce_entry);
720 rcache_invalidate();
721#endif
722 emith_tst_r_r(arg0, arg0);
723 EMITH_SJMP_START(DCOND_EQ);
724 emith_jump_reg_c(DCOND_NE, arg0);
725 EMITH_SJMP_END(DCOND_EQ);
726}
8796b7ee 727
e05b81fc 728static void REGPARM(3) *lookup_block(u32 pc, int is_slave, int *tcache_id)
729{
730 block_desc *bd = NULL;
731 void *block = NULL;
732 *tcache_id = 0;
733
734 // we have full block id tables for data_array and RAM
735 // BIOS goes to data_array table too
736 if ((pc & 0xe0000000) == 0xc0000000 || (pc & ~0xfff) == 0) {
737 int blkid = Pico32xMem->drcblk_da[is_slave][(pc & 0xfff) >> SH2_DRCBLK_DA_SHIFT];
738 *tcache_id = 1 + is_slave;
739 if (blkid & 1) {
740 bd = &block_tables[*tcache_id][blkid >> 1];
741 block = bd->tcache_ptr;
742 }
743 }
744 // RAM
745 else if ((pc & 0xc6000000) == 0x06000000) {
746 int blkid = Pico32xMem->drcblk_ram[(pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT];
747 if (blkid & 1) {
748 bd = &block_tables[0][blkid >> 1];
749 block = bd->tcache_ptr;
750 }
751 }
752 // ROM
753 else if ((pc & 0xc6000000) == 0x02000000) {
754 bd = HASH_FUNC(hash_table, pc);
8796b7ee 755
e05b81fc 756 if (bd != NULL) {
757 if (bd->addr == pc)
758 block = bd->tcache_ptr;
759 else
760 block = dr_find_block(bd, pc);
761 }
762 }
763
764#if (DRC_DEBUG & 1)
765 if (bd != NULL)
766 bd->refcount++;
767#endif
768 return block;
f0d7b1fa 769}
679af8a3 770
44e6452e 771void dr_link_blocks(void *target, u32 pc, int tcache_id)
772{
773 block_link *bl = block_links[tcache_id];
774 int cnt = block_link_counts[tcache_id];
775 int i;
776
777 for (i = 0; i < cnt; i++) {
778 if (bl[i].target_pc == pc) {
779 dbg(1, "- link from %p", bl[i].jump);
780 emith_jump_patch(bl[i].jump, target);
781 // XXX: sync ARM caches (old jump should be fine)?
782 }
783 }
784}
785
786void *dr_prepare_ext_branch(u32 pc, SH2 *sh2, int tcache_id)
787{
788 int target_tcache_id;
789 void *target;
790 int ret;
791
792 target = lookup_block(pc, sh2->is_slave, &target_tcache_id);
793 if (target_tcache_id == tcache_id) {
794 // allow linking blocks only from local cache
795 ret = dr_add_block_link(pc, tcache_ptr, tcache_id);
796 if (ret < 0)
797 return NULL;
798 }
799 if (target == NULL || target_tcache_id != tcache_id)
800 target = sh2_drc_dispatcher;
801
802 return target;
803}
804
e898de13 805#define DELAYED_OP \
18b94127 806 drcf.delayed_op = 2
807
808#define DELAY_SAVE_T(sr) { \
809 emith_bic_r_imm(sr, T_save); \
810 emith_tst_r_imm(sr, T); \
811 EMITH_SJMP_START(DCOND_EQ); \
812 emith_or_r_imm_c(DCOND_NE, sr, T_save); \
813 EMITH_SJMP_END(DCOND_EQ); \
814 drcf.use_saved_t = 1; \
815}
e898de13 816
e05b81fc 817#define FLUSH_CYCLES(sr) \
818 if (cycles > 0) { \
819 emith_sub_r_imm(sr, cycles << 12); \
820 cycles = 0; \
821 }
822
e898de13 823#define CHECK_UNHANDLED_BITS(mask) { \
824 if ((op & (mask)) != 0) \
825 goto default_; \
826}
827
80599a42 828#define GET_Fx() \
829 ((op >> 4) & 0x0f)
830
831#define GET_Rm GET_Fx
832
833#define GET_Rn() \
834 ((op >> 8) & 0x0f)
835
ed8cf79b 836#define CHECK_FX_LT(n) \
52d759c3 837 if (GET_Fx() >= n) \
80599a42 838 goto default_
839
44e6452e 840#define MAX_LOCAL_BRANCHES 32
18b94127 841
842// op_flags: data from 1st pass
843#define OP_FLAGS(pc) op_flags[((pc) - base_pc) / 2]
844#define OF_DELAY_OP (1 << 0)
845
e05b81fc 846static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
679af8a3 847{
18b94127 848 // XXX: maybe use structs instead?
849 void *branch_target_ptr[MAX_LOCAL_BRANCHES];
850 u32 branch_target_pc[MAX_LOCAL_BRANCHES];
851 int branch_target_count = 0;
852 void *branch_patch_ptr[MAX_LOCAL_BRANCHES];
853 u32 branch_patch_pc[MAX_LOCAL_BRANCHES];
854 int branch_patch_count = 0;
44e6452e 855 int pending_branch_cond = -1;
856 int pending_branch_pc = 0;
18b94127 857 u8 op_flags[BLOCK_CYCLE_LIMIT + 1];
858 struct {
859 u32 delayed_op:2;
860 u32 test_irq:1;
861 u32 use_saved_t:1; // delayed op modifies T
862 } drcf = { 0, };
863
44e6452e 864 // PC of current, first, last, last_target_blk SH2 insn
865 u32 pc, base_pc, end_pc, out_pc;
f4bb5d6b 866 void *block_entry;
679af8a3 867 block_desc *this_block;
18b94127 868 int blkid_main = 0;
869 u32 tmp, tmp2;
870 int cycles;
871 int op;
872 int i;
873
874 base_pc = sh2->pc;
679af8a3 875
f4bb5d6b 876 // validate PC
18b94127 877 tmp = base_pc >> 29;
878 if ((tmp != 0 && tmp != 1 && tmp != 6) || base_pc == 0) {
879 printf("invalid PC, aborting: %08x\n", base_pc);
f4bb5d6b 880 // FIXME: be less destructive
881 exit(1);
882 }
883
f4bb5d6b 884 tcache_ptr = tcache_ptrs[tcache_id];
18b94127 885 this_block = dr_add_block(base_pc, tcache_id, &blkid_main);
44e6452e 886 if (this_block == NULL)
887 return NULL;
f4bb5d6b 888
18b94127 889 // predict tcache overflow
f4bb5d6b 890 tmp = tcache_ptr - tcache_bases[tcache_id];
44e6452e 891 if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE) {
892 printf("tcache %d overflow\n", tcache_id);
18b94127 893 return NULL;
44e6452e 894 }
18b94127 895
896 block_entry = tcache_ptr;
897 dbg(1, "== %csh2 block #%d,%d %08x -> %p", sh2->is_slave ? 's' : 'm',
898 tcache_id, blkid_main, base_pc, block_entry);
899
44e6452e 900 dr_link_blocks(tcache_ptr, base_pc, tcache_id);
901
18b94127 902 // 1st pass: scan forward for local branches
903 memset(op_flags, 0, sizeof(op_flags));
904 for (cycles = 0, pc = base_pc; cycles < BLOCK_CYCLE_LIMIT; cycles++, pc += 2) {
905 op = p32x_sh2_read16(pc, sh2);
906 if ((op & 0xf000) == 0xa000 || (op & 0xf000) == 0xb000) { // BRA, BSR
44e6452e 907 signed int offs = ((signed int)(op << 20) >> 19);
18b94127 908 pc += 2;
909 OP_FLAGS(pc) |= OF_DELAY_OP;
44e6452e 910 ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc + offs + 2,);
18b94127 911 break;
912 }
913 if ((op & 0xf000) == 0) {
914 op &= 0xff;
44e6452e 915 if (op == 0x1b) // SLEEP
916 break;
917 if (op == 0x23 || op == 0x03 || op == 0x0b || op == 0x2b) { // BRAF, BSRF, RTS, RTE
18b94127 918 pc += 2;
919 OP_FLAGS(pc) |= OF_DELAY_OP;
920 break;
921 }
922 continue;
923 }
924 if ((op & 0xf0df) == 0x400b) { // JMP, JSR
925 pc += 2;
926 OP_FLAGS(pc) |= OF_DELAY_OP;
927 break;
928 }
929 if ((op & 0xf900) == 0x8900) { // BT(S), BF(S)
930 signed int offs = ((signed int)(op << 24) >> 23);
931 if (op & 0x0400)
932 OP_FLAGS(pc + 2) |= OF_DELAY_OP;
44e6452e 933 ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc + offs + 4, break);
18b94127 934 }
44e6452e 935 if ((op & 0xff00) == 0xc300) // TRAPA
936 break;
f4bb5d6b 937 }
e898de13 938
18b94127 939 end_pc = pc;
679af8a3 940
18b94127 941 // clean branch_targets that are not really local,
942 // and that land on delay slots
943 for (i = 0, tmp = 0; i < branch_target_count; i++) {
944 pc = branch_target_pc[i];
945 if (base_pc <= pc && pc <= end_pc && !(OP_FLAGS(pc) & OF_DELAY_OP))
946 branch_target_pc[tmp++] = branch_target_pc[i];
e898de13 947 }
18b94127 948 branch_target_count = tmp;
949 memset(branch_target_ptr, 0, sizeof(branch_target_ptr[0]) * branch_target_count);
679af8a3 950
18b94127 951 // -------------------------------------------------
952 // 2nd pass: actual compilation
44e6452e 953 out_pc = 0;
18b94127 954 pc = base_pc;
955 for (cycles = 0; pc <= end_pc || drcf.delayed_op; )
679af8a3 956 {
18b94127 957 u32 tmp3, tmp4, sr;
958
959 if (drcf.delayed_op > 0)
960 drcf.delayed_op--;
961
962 i = find_in_array(branch_target_pc, branch_target_count, pc);
963 if (i >= 0)
964 {
965 if (pc != sh2->pc)
966 {
967 /* make "subblock" - just a mid-block entry */
968 block_desc *subblock;
969 u16 *drcblk;
970 int blkid;
971
972 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 973 FLUSH_CYCLES(sr);
18b94127 974 rcache_flush();
975 do_host_disasm(tcache_id);
976
977 subblock = dr_add_block(pc, tcache_id, &blkid);
978 if (subblock == NULL)
979 return NULL;
980 subblock->end_addr = pc;
981
982 if (tcache_id != 0) { // data array, BIOS
983 drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
984 drcblk += (pc & 0x00fff) >> SH2_DRCBLK_DA_SHIFT;
985 *drcblk = (blkid << 1) | 1;
986 } else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
987 drcblk = Pico32xMem->drcblk_ram;
988 drcblk += (pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
989 *drcblk = (blkid << 1) | 1;
990 }
991
44e6452e 992 dbg(1, "-- %csh2 subblock #%d,%d %08x -> %p", sh2->is_slave ? 's' : 'm',
18b94127 993 tcache_id, blkid, pc, tcache_ptr);
44e6452e 994
995 // since we made a block entry, link any other blocks that jump to current pc
996 dr_link_blocks(tcache_ptr, pc, tcache_id);
18b94127 997 }
998 branch_target_ptr[i] = tcache_ptr;
999
1000 // must update PC
1001 emit_move_r_imm32(SHR_PC, pc);
1002 rcache_clean();
1003
1004 // check cycles
1005 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
1006 emith_cmp_r_imm(sr, 0);
1007 emith_jump_cond(DCOND_LE, sh2_drc_exit);
1008 }
e898de13 1009
2b2b46b0 1010 op = p32x_sh2_read16(pc, sh2);
e898de13 1011
1012#if (DRC_DEBUG & 3)
1013 insns_compiled++;
1014#if (DRC_DEBUG & 2)
1015 DasmSH2(sh2dasm_buff, pc, op);
1016 printf("%08x %04x %s\n", pc, op, sh2dasm_buff);
1017#endif
679af8a3 1018#endif
679af8a3 1019
1020 pc += 2;
1021 cycles++;
1022
1023 switch ((op >> 12) & 0x0f)
1024 {
3863edbd 1025 /////////////////////////////////////////////
679af8a3 1026 case 0x00:
80599a42 1027 switch (op & 0x0f)
1028 {
1029 case 0x02:
1030 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1031 switch (GET_Fx())
1032 {
1033 case 0: // STC SR,Rn 0000nnnn00000010
1034 tmp2 = SHR_SR;
1035 break;
1036 case 1: // STC GBR,Rn 0000nnnn00010010
1037 tmp2 = SHR_GBR;
1038 break;
1039 case 2: // STC VBR,Rn 0000nnnn00100010
1040 tmp2 = SHR_VBR;
1041 break;
1042 default:
1043 goto default_;
1044 }
ed8cf79b 1045 tmp3 = rcache_get_reg(tmp2, RC_GR_READ);
1046 emith_move_r_r(tmp, tmp3);
1047 if (tmp2 == SHR_SR)
18b94127 1048 emith_clear_msb(tmp, tmp, 22); // reserved bits defined by ISA as 0
80599a42 1049 goto end_op;
e898de13 1050 case 0x03:
1051 CHECK_UNHANDLED_BITS(0xd0);
1052 // BRAF Rm 0000mmmm00100011
1053 // BSRF Rm 0000mmmm00000011
679af8a3 1054 DELAYED_OP;
18b94127 1055 tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE);
80599a42 1056 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
c18edb34 1057 emith_move_r_r(tmp, tmp2);
18b94127 1058 if (op & 0x20)
1059 emith_add_r_imm(tmp, pc + 2);
1060 else { // BSRF
1061 tmp3 = rcache_get_reg(SHR_PR, RC_GR_WRITE);
1062 emith_move_r_imm(tmp3, pc + 2);
1063 emith_add_r_r(tmp, tmp3);
1064 }
44e6452e 1065 out_pc = (u32)-1;
679af8a3 1066 cycles++;
e898de13 1067 goto end_op;
80599a42 1068 case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
1069 case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
1070 case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
e05b81fc 1071 rcache_clean();
1072 tmp = rcache_get_reg_arg(1, GET_Rm());
1073 tmp2 = rcache_get_reg_arg(0, SHR_R0);
1074 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1075 emith_add_r_r(tmp2, tmp3);
1076 emit_memhandler_write(op & 3, pc, drcf.delayed_op);
80599a42 1077 goto end_op;
1078 case 0x07:
1079 // MUL.L Rm,Rn 0000nnnnmmmm0111
1080 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1081 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1082 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1083 emith_mul(tmp3, tmp2, tmp);
1084 cycles++;
1085 goto end_op;
1086 case 0x08:
1087 CHECK_UNHANDLED_BITS(0xf00);
1088 switch (GET_Fx())
1089 {
1090 case 0: // CLRT 0000000000001000
8796b7ee 1091 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1092 if (drcf.delayed_op)
1093 DELAY_SAVE_T(sr);
8796b7ee 1094 emith_bic_r_imm(sr, T);
80599a42 1095 break;
1096 case 1: // SETT 0000000000011000
8796b7ee 1097 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1098 if (drcf.delayed_op)
1099 DELAY_SAVE_T(sr);
8796b7ee 1100 emith_or_r_imm(sr, T);
80599a42 1101 break;
1102 case 2: // CLRMAC 0000000000101000
1103 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1104 emith_move_r_imm(tmp, 0);
1105 tmp = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1106 emith_move_r_imm(tmp, 0);
1107 break;
1108 default:
1109 goto default_;
1110 }
1111 goto end_op;
e898de13 1112 case 0x09:
80599a42 1113 switch (GET_Fx())
1114 {
1115 case 0: // NOP 0000000000001001
1116 CHECK_UNHANDLED_BITS(0xf00);
1117 break;
1118 case 1: // DIV0U 0000000000011001
1119 CHECK_UNHANDLED_BITS(0xf00);
8796b7ee 1120 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1121 if (drcf.delayed_op)
1122 DELAY_SAVE_T(sr);
8796b7ee 1123 emith_bic_r_imm(sr, M|Q|T);
80599a42 1124 break;
1125 case 2: // MOVT Rn 0000nnnn00101001
8796b7ee 1126 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
80599a42 1127 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
8796b7ee 1128 emith_clear_msb(tmp2, sr, 31);
80599a42 1129 break;
1130 default:
1131 goto default_;
1132 }
1133 goto end_op;
1134 case 0x0a:
1135 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1136 switch (GET_Fx())
1137 {
1138 case 0: // STS MACH,Rn 0000nnnn00001010
ed8cf79b 1139 tmp2 = SHR_MACH;
80599a42 1140 break;
1141 case 1: // STS MACL,Rn 0000nnnn00011010
ed8cf79b 1142 tmp2 = SHR_MACL;
80599a42 1143 break;
1144 case 2: // STS PR,Rn 0000nnnn00101010
ed8cf79b 1145 tmp2 = SHR_PR;
80599a42 1146 break;
1147 default:
1148 goto default_;
1149 }
ed8cf79b 1150 tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
80599a42 1151 emith_move_r_r(tmp, tmp2);
e898de13 1152 goto end_op;
1153 case 0x0b:
80599a42 1154 CHECK_UNHANDLED_BITS(0xf00);
1155 switch (GET_Fx())
1156 {
1157 case 0: // RTS 0000000000001011
1158 DELAYED_OP;
18b94127 1159 emit_move_r_r(SHR_PC, SHR_PR);
44e6452e 1160 out_pc = (u32)-1;
e898de13 1161 cycles++;
80599a42 1162 break;
1163 case 1: // SLEEP 0000000000011011
80599a42 1164 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
1165 emith_clear_msb(tmp, tmp, 20); // clear cycles
44e6452e 1166 out_pc = out_pc - 2;
80599a42 1167 cycles = 1;
e05b81fc 1168 goto end_op;
80599a42 1169 case 2: // RTE 0000000000101011
52d759c3 1170 DELAYED_OP;
1171 rcache_clean();
1172 // pop PC
1173 rcache_get_reg_arg(0, SHR_SP);
1174 tmp = emit_memhandler_read(2);
18b94127 1175 tmp2 = rcache_get_reg(SHR_PC, RC_GR_WRITE);
52d759c3 1176 emith_move_r_r(tmp2, tmp);
1177 rcache_free_tmp(tmp);
1178 rcache_clean();
1179 // pop SR
1180 tmp = rcache_get_reg_arg(0, SHR_SP);
1181 emith_add_r_imm(tmp, 4);
1182 tmp = emit_memhandler_read(2);
18b94127 1183 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1184 emith_write_sr(sr, tmp);
52d759c3 1185 rcache_free_tmp(tmp);
1186 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
1187 emith_add_r_imm(tmp, 4*2);
18b94127 1188 drcf.test_irq = 1;
44e6452e 1189 out_pc = (u32)-1;
e898de13 1190 cycles += 3;
80599a42 1191 break;
1192 default:
1193 goto default_;
e898de13 1194 }
1195 goto end_op;
80599a42 1196 case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
1197 case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
1198 case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
52d759c3 1199 tmp = emit_indirect_indexed_read(SHR_R0, GET_Rm(), op & 3);
80599a42 1200 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
80599a42 1201 if ((op & 3) != 2) {
1202 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
1203 } else
1204 emith_move_r_r(tmp2, tmp);
52d759c3 1205 rcache_free_tmp(tmp);
80599a42 1206 goto end_op;
1207 case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
f0d7b1fa 1208 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
8796b7ee 1209 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
f0d7b1fa 1210 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
1211 /* MS 16 MAC bits unused if saturated */
8796b7ee 1212 emith_tst_r_imm(sr, S);
f0d7b1fa 1213 EMITH_SJMP_START(DCOND_EQ);
1214 emith_clear_msb_c(DCOND_NE, tmp4, tmp4, 16);
1215 EMITH_SJMP_END(DCOND_EQ);
1216 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW); // might evict SR
1217 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 1218 rcache_free_tmp(tmp2);
8796b7ee 1219 sr = rcache_get_reg(SHR_SR, RC_GR_READ); // reget just in case
1220 emith_tst_r_imm(sr, S);
1221
1222 EMITH_JMP_START(DCOND_EQ);
1223 emith_asr(tmp, tmp4, 15);
1224 emith_cmp_r_imm(tmp, -1); // negative overflow (0x80000000..0xffff7fff)
1225 EMITH_SJMP_START(DCOND_GE);
1226 emith_move_r_imm_c(DCOND_LT, tmp4, 0x8000);
1227 emith_move_r_imm_c(DCOND_LT, tmp3, 0x0000);
1228 EMITH_SJMP_END(DCOND_GE);
1229 emith_cmp_r_imm(tmp, 0); // positive overflow (0x00008000..0x7fffffff)
1230 EMITH_SJMP_START(DCOND_LE);
1231 emith_move_r_imm_c(DCOND_GT, tmp4, 0x00007fff);
1232 emith_move_r_imm_c(DCOND_GT, tmp3, 0xffffffff);
1233 EMITH_SJMP_END(DCOND_LE);
1234 EMITH_JMP_END(DCOND_EQ);
1235
1236 rcache_free_tmp(tmp);
f0d7b1fa 1237 cycles += 3;
1238 goto end_op;
80599a42 1239 }
1240 goto default_;
1241
3863edbd 1242 /////////////////////////////////////////////
80599a42 1243 case 0x01:
1244 // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
1245 rcache_clean();
1246 tmp = rcache_get_reg_arg(0, GET_Rn());
1247 tmp2 = rcache_get_reg_arg(1, GET_Rm());
1248 emith_add_r_imm(tmp, (op & 0x0f) * 4);
e05b81fc 1249 emit_memhandler_write(2, pc, drcf.delayed_op);
80599a42 1250 goto end_op;
1251
1252 case 0x02:
1253 switch (op & 0x0f)
1254 {
1255 case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
1256 case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
1257 case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
1258 rcache_clean();
1259 rcache_get_reg_arg(0, GET_Rn());
1260 rcache_get_reg_arg(1, GET_Rm());
e05b81fc 1261 emit_memhandler_write(op & 3, pc, drcf.delayed_op);
80599a42 1262 goto end_op;
1263 case 0x04: // MOV.B Rm,@–Rn 0010nnnnmmmm0100
1264 case 0x05: // MOV.W Rm,@–Rn 0010nnnnmmmm0101
1265 case 0x06: // MOV.L Rm,@–Rn 0010nnnnmmmm0110
1266 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1267 emith_sub_r_imm(tmp, (1 << (op & 3)));
1268 rcache_clean();
1269 rcache_get_reg_arg(0, GET_Rn());
1270 rcache_get_reg_arg(1, GET_Rm());
e05b81fc 1271 emit_memhandler_write(op & 3, pc, drcf.delayed_op);
80599a42 1272 goto end_op;
1273 case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
8796b7ee 1274 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
80599a42 1275 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1276 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
18b94127 1277 if (drcf.delayed_op)
1278 DELAY_SAVE_T(sr);
8796b7ee 1279 emith_bic_r_imm(sr, M|Q|T);
80599a42 1280 emith_tst_r_imm(tmp2, (1<<31));
1281 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 1282 emith_or_r_imm_c(DCOND_NE, sr, Q);
80599a42 1283 EMITH_SJMP_END(DCOND_EQ);
1284 emith_tst_r_imm(tmp3, (1<<31));
1285 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 1286 emith_or_r_imm_c(DCOND_NE, sr, M);
80599a42 1287 EMITH_SJMP_END(DCOND_EQ);
1288 emith_teq_r_r(tmp2, tmp3);
1289 EMITH_SJMP_START(DCOND_PL);
8796b7ee 1290 emith_or_r_imm_c(DCOND_MI, sr, T);
80599a42 1291 EMITH_SJMP_END(DCOND_PL);
1292 goto end_op;
3863edbd 1293 case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
8796b7ee 1294 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1295 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1296 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
18b94127 1297 if (drcf.delayed_op)
1298 DELAY_SAVE_T(sr);
8796b7ee 1299 emith_bic_r_imm(sr, T);
3863edbd 1300 emith_tst_r_r(tmp2, tmp3);
8796b7ee 1301 emit_or_t_if_eq(sr);
3863edbd 1302 goto end_op;
1303 case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
1304 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1305 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1306 emith_and_r_r(tmp, tmp2);
1307 goto end_op;
1308 case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
1309 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1310 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1311 emith_eor_r_r(tmp, tmp2);
1312 goto end_op;
1313 case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
1314 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1315 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1316 emith_or_r_r(tmp, tmp2);
1317 goto end_op;
1318 case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
1319 tmp = rcache_get_tmp();
1320 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1321 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1322 emith_eor_r_r_r(tmp, tmp2, tmp3);
8796b7ee 1323 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1324 if (drcf.delayed_op)
1325 DELAY_SAVE_T(sr);
8796b7ee 1326 emith_bic_r_imm(sr, T);
3863edbd 1327 emith_tst_r_imm(tmp, 0x000000ff);
52d759c3 1328 emit_or_t_if_eq(tmp);
3863edbd 1329 emith_tst_r_imm(tmp, 0x0000ff00);
52d759c3 1330 emit_or_t_if_eq(tmp);
3863edbd 1331 emith_tst_r_imm(tmp, 0x00ff0000);
52d759c3 1332 emit_or_t_if_eq(tmp);
3863edbd 1333 emith_tst_r_imm(tmp, 0xff000000);
52d759c3 1334 emit_or_t_if_eq(tmp);
3863edbd 1335 rcache_free_tmp(tmp);
1336 goto end_op;
1337 case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
1338 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1339 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1340 emith_lsr(tmp, tmp, 16);
f0d7b1fa 1341 emith_or_r_r_lsl(tmp, tmp2, 16);
3863edbd 1342 goto end_op;
1343 case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
1344 case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
1345 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1346 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1347 if (op & 1) {
1348 emith_sext(tmp, tmp2, 16);
1349 } else
1350 emith_clear_msb(tmp, tmp2, 16);
1351 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1352 tmp2 = rcache_get_tmp();
1353 if (op & 1) {
1354 emith_sext(tmp2, tmp3, 16);
1355 } else
1356 emith_clear_msb(tmp2, tmp3, 16);
1357 emith_mul(tmp, tmp, tmp2);
1358 rcache_free_tmp(tmp2);
1359// FIXME: causes timing issues in Doom?
1360// cycles++;
1361 goto end_op;
679af8a3 1362 }
1363 goto default_;
1364
3863edbd 1365 /////////////////////////////////////////////
1366 case 0x03:
1367 switch (op & 0x0f)
1368 {
1369 case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
1370 case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
1371 case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
1372 case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
1373 case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
8796b7ee 1374 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1375 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1376 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
18b94127 1377 if (drcf.delayed_op)
1378 DELAY_SAVE_T(sr);
8796b7ee 1379 emith_bic_r_imm(sr, T);
3863edbd 1380 emith_cmp_r_r(tmp2, tmp3);
1381 switch (op & 0x07)
1382 {
1383 case 0x00: // CMP/EQ
8796b7ee 1384 emit_or_t_if_eq(sr);
3863edbd 1385 break;
1386 case 0x02: // CMP/HS
1387 EMITH_SJMP_START(DCOND_LO);
8796b7ee 1388 emith_or_r_imm_c(DCOND_HS, sr, T);
3863edbd 1389 EMITH_SJMP_END(DCOND_LO);
1390 break;
1391 case 0x03: // CMP/GE
1392 EMITH_SJMP_START(DCOND_LT);
8796b7ee 1393 emith_or_r_imm_c(DCOND_GE, sr, T);
3863edbd 1394 EMITH_SJMP_END(DCOND_LT);
1395 break;
1396 case 0x06: // CMP/HI
1397 EMITH_SJMP_START(DCOND_LS);
8796b7ee 1398 emith_or_r_imm_c(DCOND_HI, sr, T);
3863edbd 1399 EMITH_SJMP_END(DCOND_LS);
1400 break;
1401 case 0x07: // CMP/GT
1402 EMITH_SJMP_START(DCOND_LE);
8796b7ee 1403 emith_or_r_imm_c(DCOND_GT, sr, T);
3863edbd 1404 EMITH_SJMP_END(DCOND_LE);
1405 break;
1406 }
1407 goto end_op;
1408 case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
f0d7b1fa 1409 // Q1 = carry(Rn = (Rn << 1) | T)
1410 // if Q ^ M
1411 // Q2 = carry(Rn += Rm)
1412 // else
1413 // Q2 = carry(Rn -= Rm)
1414 // Q = M ^ Q1 ^ Q2
1415 // T = (Q == M) = !(Q ^ M) = !(Q1 ^ Q2)
1416 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1417 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1418 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1419 if (drcf.delayed_op)
1420 DELAY_SAVE_T(sr);
8b4f38f4 1421 emith_tpop_carry(sr, 0);
f0d7b1fa 1422 emith_adcf_r_r(tmp2, tmp2);
8b4f38f4 1423 emith_tpush_carry(sr, 0); // keep Q1 in T for now
f0d7b1fa 1424 tmp4 = rcache_get_tmp();
1425 emith_and_r_r_imm(tmp4, sr, M);
1426 emith_eor_r_r_lsr(sr, tmp4, M_SHIFT - Q_SHIFT); // Q ^= M
1427 rcache_free_tmp(tmp4);
1428 // add or sub, invert T if carry to get Q1 ^ Q2
1429 // in: (Q ^ M) passed in Q, Q1 in T
1430 emith_sh2_div1_step(tmp2, tmp3, sr);
18b94127 1431 emith_bic_r_imm(sr, Q);
1432 emith_tst_r_imm(sr, M);
1433 EMITH_SJMP_START(DCOND_EQ);
1434 emith_or_r_imm_c(DCOND_NE, sr, Q); // Q = M
1435 EMITH_SJMP_END(DCOND_EQ);
1436 emith_tst_r_imm(sr, T);
1437 EMITH_SJMP_START(DCOND_EQ);
1438 emith_eor_r_imm_c(DCOND_NE, sr, Q); // Q = M ^ Q1 ^ Q2
1439 EMITH_SJMP_END(DCOND_EQ);
1440 emith_eor_r_imm(sr, T); // T = !(Q1 ^ Q2)
f0d7b1fa 1441 goto end_op;
3863edbd 1442 case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
1443 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1444 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1445 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1446 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1447 emith_mul_u64(tmp3, tmp4, tmp, tmp2);
1448 goto end_op;
1449 case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
1450 case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
1451 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1452 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1453 if (op & 4) {
1454 emith_add_r_r(tmp, tmp2);
1455 } else
1456 emith_sub_r_r(tmp, tmp2);
1457 goto end_op;
1458 case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
1459 case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
1460 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1461 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1462 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1463 if (drcf.delayed_op)
1464 DELAY_SAVE_T(sr);
3863edbd 1465 if (op & 4) { // adc
8b4f38f4 1466 emith_tpop_carry(sr, 0);
3863edbd 1467 emith_adcf_r_r(tmp, tmp2);
8b4f38f4 1468 emith_tpush_carry(sr, 0);
3863edbd 1469 } else {
8b4f38f4 1470 emith_tpop_carry(sr, 1);
3863edbd 1471 emith_sbcf_r_r(tmp, tmp2);
8b4f38f4 1472 emith_tpush_carry(sr, 1);
3863edbd 1473 }
3863edbd 1474 goto end_op;
1475 case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
1476 case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
1477 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1478 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1479 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1480 if (drcf.delayed_op)
1481 DELAY_SAVE_T(sr);
8796b7ee 1482 emith_bic_r_imm(sr, T);
3863edbd 1483 if (op & 4) {
1484 emith_addf_r_r(tmp, tmp2);
1485 } else
1486 emith_subf_r_r(tmp, tmp2);
1487 EMITH_SJMP_START(DCOND_VC);
8796b7ee 1488 emith_or_r_imm_c(DCOND_VS, sr, T);
3863edbd 1489 EMITH_SJMP_END(DCOND_VC);
1490 goto end_op;
1491 case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
1492 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1493 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1494 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1495 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1496 emith_mul_s64(tmp3, tmp4, tmp, tmp2);
1497 goto end_op;
1498 }
1499 goto default_;
1500
1501 /////////////////////////////////////////////
679af8a3 1502 case 0x04:
3863edbd 1503 switch (op & 0x0f)
1504 {
c18edb34 1505 case 0x00:
3863edbd 1506 switch (GET_Fx())
1507 {
1508 case 0: // SHLL Rn 0100nnnn00000000
1509 case 2: // SHAL Rn 0100nnnn00100000
8796b7ee 1510 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1511 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1512 if (drcf.delayed_op)
1513 DELAY_SAVE_T(sr);
8b4f38f4 1514 emith_tpop_carry(sr, 0); // dummy
3863edbd 1515 emith_lslf(tmp, tmp, 1);
8b4f38f4 1516 emith_tpush_carry(sr, 0);
3863edbd 1517 goto end_op;
1518 case 1: // DT Rn 0100nnnn00010000
1519 if (p32x_sh2_read16(pc, sh2) == 0x8bfd) { // BF #-2
1520 emith_sh2_dtbf_loop();
1521 goto end_op;
1522 }
1523 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
8796b7ee 1524 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1525 if (drcf.delayed_op)
1526 DELAY_SAVE_T(sr);
8796b7ee 1527 emith_bic_r_imm(sr, T);
3863edbd 1528 emith_subf_r_imm(tmp, 1);
8796b7ee 1529 emit_or_t_if_eq(sr);
80599a42 1530 goto end_op;
1531 }
3863edbd 1532 goto default_;
ed8cf79b 1533 case 0x01:
1534 switch (GET_Fx())
1535 {
1536 case 0: // SHLR Rn 0100nnnn00000001
1537 case 2: // SHAR Rn 0100nnnn00100001
8796b7ee 1538 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1539 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1540 if (drcf.delayed_op)
1541 DELAY_SAVE_T(sr);
8b4f38f4 1542 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 1543 if (op & 0x20) {
1544 emith_asrf(tmp, tmp, 1);
1545 } else
1546 emith_lsrf(tmp, tmp, 1);
8b4f38f4 1547 emith_tpush_carry(sr, 0);
ed8cf79b 1548 goto end_op;
1549 case 1: // CMP/PZ Rn 0100nnnn00010001
8796b7ee 1550 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1551 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1552 if (drcf.delayed_op)
1553 DELAY_SAVE_T(sr);
8796b7ee 1554 emith_bic_r_imm(sr, T);
ed8cf79b 1555 emith_cmp_r_imm(tmp, 0);
1556 EMITH_SJMP_START(DCOND_LT);
8796b7ee 1557 emith_or_r_imm_c(DCOND_GE, sr, T);
ed8cf79b 1558 EMITH_SJMP_END(DCOND_LT);
1559 goto end_op;
1560 }
1561 goto default_;
1562 case 0x02:
1563 case 0x03:
1564 switch (op & 0x3f)
1565 {
1566 case 0x02: // STS.L MACH,@–Rn 0100nnnn00000010
1567 tmp = SHR_MACH;
1568 break;
1569 case 0x12: // STS.L MACL,@–Rn 0100nnnn00010010
1570 tmp = SHR_MACL;
1571 break;
1572 case 0x22: // STS.L PR,@–Rn 0100nnnn00100010
1573 tmp = SHR_PR;
1574 break;
1575 case 0x03: // STC.L SR,@–Rn 0100nnnn00000011
1576 tmp = SHR_SR;
1577 break;
1578 case 0x13: // STC.L GBR,@–Rn 0100nnnn00010011
1579 tmp = SHR_GBR;
1580 break;
1581 case 0x23: // STC.L VBR,@–Rn 0100nnnn00100011
1582 tmp = SHR_VBR;
1583 break;
1584 default:
e898de13 1585 goto default_;
ed8cf79b 1586 }
1587 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1588 emith_sub_r_imm(tmp2, 4);
1589 rcache_clean();
1590 rcache_get_reg_arg(0, GET_Rn());
1591 tmp3 = rcache_get_reg_arg(1, tmp);
1592 if (tmp == SHR_SR)
e05b81fc 1593 emith_clear_msb(tmp3, tmp3, 22); // reserved bits defined by ISA as 0
1594 emit_memhandler_write(2, pc, drcf.delayed_op);
ed8cf79b 1595 goto end_op;
1596 case 0x04:
1597 case 0x05:
1598 switch (op & 0x3f)
1599 {
1600 case 0x04: // ROTL Rn 0100nnnn00000100
1601 case 0x05: // ROTR Rn 0100nnnn00000101
8796b7ee 1602 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1603 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1604 if (drcf.delayed_op)
1605 DELAY_SAVE_T(sr);
8b4f38f4 1606 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 1607 if (op & 1) {
1608 emith_rorf(tmp, tmp, 1);
1609 } else
1610 emith_rolf(tmp, tmp, 1);
8b4f38f4 1611 emith_tpush_carry(sr, 0);
ed8cf79b 1612 goto end_op;
1613 case 0x24: // ROTCL Rn 0100nnnn00100100
1614 case 0x25: // ROTCR Rn 0100nnnn00100101
8796b7ee 1615 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1616 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1617 if (drcf.delayed_op)
1618 DELAY_SAVE_T(sr);
8b4f38f4 1619 emith_tpop_carry(sr, 0);
ed8cf79b 1620 if (op & 1) {
1621 emith_rorcf(tmp);
1622 } else
1623 emith_rolcf(tmp);
8b4f38f4 1624 emith_tpush_carry(sr, 0);
ed8cf79b 1625 goto end_op;
1626 case 0x15: // CMP/PL Rn 0100nnnn00010101
8796b7ee 1627 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1628 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1629 if (drcf.delayed_op)
1630 DELAY_SAVE_T(sr);
8796b7ee 1631 emith_bic_r_imm(sr, T);
ed8cf79b 1632 emith_cmp_r_imm(tmp, 0);
1633 EMITH_SJMP_START(DCOND_LE);
8796b7ee 1634 emith_or_r_imm_c(DCOND_GT, sr, T);
ed8cf79b 1635 EMITH_SJMP_END(DCOND_LE);
1636 goto end_op;
1637 }
e898de13 1638 goto default_;
ed8cf79b 1639 case 0x06:
1640 case 0x07:
1641 switch (op & 0x3f)
1642 {
1643 case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
1644 tmp = SHR_MACH;
1645 break;
1646 case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
1647 tmp = SHR_MACL;
1648 break;
1649 case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
1650 tmp = SHR_PR;
1651 break;
1652 case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
1653 tmp = SHR_SR;
1654 break;
1655 case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
1656 tmp = SHR_GBR;
1657 break;
1658 case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
1659 tmp = SHR_VBR;
1660 break;
1661 default:
1662 goto default_;
1663 }
1664 rcache_clean();
1665 rcache_get_reg_arg(0, GET_Rn());
1666 tmp2 = emit_memhandler_read(2);
1667 if (tmp == SHR_SR) {
18b94127 1668 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1669 if (drcf.delayed_op)
1670 DELAY_SAVE_T(sr);
1671 emith_write_sr(sr, tmp2);
1672 drcf.test_irq = 1;
ed8cf79b 1673 } else {
1674 tmp = rcache_get_reg(tmp, RC_GR_WRITE);
1675 emith_move_r_r(tmp, tmp2);
1676 }
1677 rcache_free_tmp(tmp2);
1678 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1679 emith_add_r_imm(tmp, 4);
1680 goto end_op;
52d759c3 1681 case 0x08:
1682 case 0x09:
1683 switch (GET_Fx())
1684 {
1685 case 0:
1686 // SHLL2 Rn 0100nnnn00001000
1687 // SHLR2 Rn 0100nnnn00001001
1688 tmp = 2;
1689 break;
1690 case 1:
1691 // SHLL8 Rn 0100nnnn00011000
1692 // SHLR8 Rn 0100nnnn00011001
1693 tmp = 8;
1694 break;
1695 case 2:
1696 // SHLL16 Rn 0100nnnn00101000
1697 // SHLR16 Rn 0100nnnn00101001
1698 tmp = 16;
1699 break;
1700 default:
1701 goto default_;
1702 }
1703 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1704 if (op & 1) {
1705 emith_lsr(tmp2, tmp2, tmp);
1706 } else
1707 emith_lsl(tmp2, tmp2, tmp);
1708 goto end_op;
1709 case 0x0a:
1710 switch (GET_Fx())
1711 {
1712 case 0: // LDS Rm,MACH 0100mmmm00001010
1713 tmp2 = SHR_MACH;
1714 break;
1715 case 1: // LDS Rm,MACL 0100mmmm00011010
1716 tmp2 = SHR_MACL;
1717 break;
1718 case 2: // LDS Rm,PR 0100mmmm00101010
1719 tmp2 = SHR_PR;
1720 break;
1721 default:
1722 goto default_;
1723 }
1724 emit_move_r_r(tmp2, GET_Rn());
1725 goto end_op;
e898de13 1726 case 0x0b:
52d759c3 1727 switch (GET_Fx())
1728 {
1729 case 0: // JSR @Rm 0100mmmm00001011
1730 case 2: // JMP @Rm 0100mmmm00101011
1731 DELAYED_OP;
1732 if (!(op & 0x20))
1733 emit_move_r_imm32(SHR_PR, pc + 2);
18b94127 1734 emit_move_r_r(SHR_PC, (op >> 8) & 0x0f);
44e6452e 1735 out_pc = (u32)-1;
52d759c3 1736 cycles++;
1737 break;
1738 case 1: // TAS.B @Rn 0100nnnn00011011
1739 // XXX: is TAS working on 32X?
1740 rcache_clean();
1741 rcache_get_reg_arg(0, GET_Rn());
8796b7ee 1742 tmp = emit_memhandler_read(0);
1743 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1744 if (drcf.delayed_op)
1745 DELAY_SAVE_T(sr);
8796b7ee 1746 emith_bic_r_imm(sr, T);
52d759c3 1747 emith_cmp_r_imm(tmp, 0);
8796b7ee 1748 emit_or_t_if_eq(sr);
52d759c3 1749 rcache_clean();
1750 emith_or_r_imm(tmp, 0x80);
1751 tmp2 = rcache_get_tmp_arg(1); // assuming it differs to tmp
1752 emith_move_r_r(tmp2, tmp);
1753 rcache_free_tmp(tmp);
1754 rcache_get_reg_arg(0, GET_Rn());
e05b81fc 1755 emit_memhandler_write(0, pc, drcf.delayed_op);
52d759c3 1756 cycles += 3;
1757 break;
1758 default:
e898de13 1759 goto default_;
52d759c3 1760 }
e898de13 1761 goto end_op;
1762 case 0x0e:
52d759c3 1763 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1764 switch (GET_Fx())
1765 {
1766 case 0: // LDC Rm,SR 0100mmmm00001110
1767 tmp2 = SHR_SR;
1768 break;
1769 case 1: // LDC Rm,GBR 0100mmmm00011110
1770 tmp2 = SHR_GBR;
1771 break;
1772 case 2: // LDC Rm,VBR 0100mmmm00101110
1773 tmp2 = SHR_VBR;
1774 break;
1775 default:
e898de13 1776 goto default_;
52d759c3 1777 }
1778 if (tmp2 == SHR_SR) {
18b94127 1779 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1780 if (drcf.delayed_op)
1781 DELAY_SAVE_T(sr);
1782 emith_write_sr(sr, tmp);
1783 drcf.test_irq = 1;
52d759c3 1784 } else {
1785 tmp2 = rcache_get_reg(tmp2, RC_GR_WRITE);
1786 emith_move_r_r(tmp2, tmp);
1787 }
1788 goto end_op;
1789 case 0x0f:
1790 // MAC @Rm+,@Rn+ 0100nnnnmmmm1111
f0d7b1fa 1791 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 1);
1792 emith_sext(tmp, tmp, 16);
1793 emith_sext(tmp2, tmp2, 16);
1794 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW);
1795 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
1796 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 1797 rcache_free_tmp(tmp2);
f0d7b1fa 1798 // XXX: MACH should be untouched when S is set?
8796b7ee 1799 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
1800 emith_tst_r_imm(sr, S);
1801 EMITH_JMP_START(DCOND_EQ);
1802
1803 emith_asr(tmp, tmp3, 31);
1804 emith_eorf_r_r(tmp, tmp4); // tmp = ((signed)macl >> 31) ^ mach
1805 EMITH_JMP_START(DCOND_EQ);
1806 emith_move_r_imm(tmp3, 0x80000000);
1807 emith_tst_r_r(tmp4, tmp4);
1808 EMITH_SJMP_START(DCOND_MI);
1809 emith_sub_r_imm_c(DCOND_PL, tmp3, 1); // positive
1810 EMITH_SJMP_END(DCOND_MI);
1811 EMITH_JMP_END(DCOND_EQ);
1812
1813 EMITH_JMP_END(DCOND_EQ);
1814 rcache_free_tmp(tmp);
f0d7b1fa 1815 cycles += 2;
1816 goto end_op;
679af8a3 1817 }
1818 goto default_;
1819
52d759c3 1820 /////////////////////////////////////////////
1821 case 0x05:
1822 // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
1823 rcache_clean();
1824 tmp = rcache_get_reg_arg(0, GET_Rm());
1825 emith_add_r_imm(tmp, (op & 0x0f) * 4);
1826 tmp = emit_memhandler_read(2);
1827 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1828 emith_move_r_r(tmp2, tmp);
1829 rcache_free_tmp(tmp);
1830 goto end_op;
1831
1832 /////////////////////////////////////////////
1833 case 0x06:
1834 switch (op & 0x0f)
1835 {
1836 case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
1837 case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
1838 case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
1839 case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
1840 case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
1841 case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
1842 rcache_clean();
1843 rcache_get_reg_arg(0, GET_Rm());
1844 tmp = emit_memhandler_read(op & 3);
1845 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1846 if ((op & 3) != 2) {
1847 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
1848 } else
1849 emith_move_r_r(tmp2, tmp);
1850 rcache_free_tmp(tmp);
1851 if ((op & 7) >= 4 && GET_Rn() != GET_Rm()) {
1852 tmp = rcache_get_reg(GET_Rm(), RC_GR_RMW);
1853 emith_add_r_imm(tmp, (1 << (op & 3)));
1854 }
1855 goto end_op;
1856 case 0x03:
1857 case 0x07 ... 0x0f:
1858 tmp = rcache_get_reg(GET_Rm(), RC_GR_READ);
1859 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1860 switch (op & 0x0f)
1861 {
1862 case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
1863 emith_move_r_r(tmp2, tmp);
1864 break;
1865 case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
1866 emith_mvn_r_r(tmp2, tmp);
1867 break;
1868 case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
1869 tmp3 = tmp2;
1870 if (tmp == tmp2)
1871 tmp3 = rcache_get_tmp();
1872 tmp4 = rcache_get_tmp();
1873 emith_lsr(tmp3, tmp, 16);
f0d7b1fa 1874 emith_or_r_r_lsl(tmp3, tmp, 24);
52d759c3 1875 emith_and_r_r_imm(tmp4, tmp, 0xff00);
f0d7b1fa 1876 emith_or_r_r_lsl(tmp3, tmp4, 8);
52d759c3 1877 emith_rol(tmp2, tmp3, 16);
1878 rcache_free_tmp(tmp4);
1879 if (tmp == tmp2)
1880 rcache_free_tmp(tmp3);
1881 break;
1882 case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
1883 emith_rol(tmp2, tmp, 16);
1884 break;
1885 case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
8796b7ee 1886 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1887 if (drcf.delayed_op)
1888 DELAY_SAVE_T(sr);
8b4f38f4 1889 emith_tpop_carry(sr, 1);
52d759c3 1890 emith_negcf_r_r(tmp2, tmp);
8b4f38f4 1891 emith_tpush_carry(sr, 1);
52d759c3 1892 break;
1893 case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
1894 emith_neg_r_r(tmp2, tmp);
1895 break;
1896 case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
1897 emith_clear_msb(tmp2, tmp, 24);
1898 break;
1899 case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
1900 emith_clear_msb(tmp2, tmp, 16);
1901 break;
1902 case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
1903 emith_sext(tmp2, tmp, 8);
1904 break;
1905 case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
1906 emith_sext(tmp2, tmp, 16);
1907 break;
1908 }
1909 goto end_op;
1910 }
1911 goto default_;
1912
1913 /////////////////////////////////////////////
1914 case 0x07:
1915 // ADD #imm,Rn 0111nnnniiiiiiii
1916 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1917 if (op & 0x80) { // adding negative
1918 emith_sub_r_imm(tmp, -op & 0xff);
1919 } else
1920 emith_add_r_imm(tmp, op & 0xff);
1921 goto end_op;
1922
3863edbd 1923 /////////////////////////////////////////////
e898de13 1924 case 0x08:
52d759c3 1925 switch (op & 0x0f00)
1926 {
1927 case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
1928 case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
1929 rcache_clean();
1930 tmp = rcache_get_reg_arg(0, GET_Rm());
1931 tmp2 = rcache_get_reg_arg(1, SHR_R0);
1932 tmp3 = (op & 0x100) >> 8;
1933 emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
e05b81fc 1934 emit_memhandler_write(tmp3, pc, drcf.delayed_op);
52d759c3 1935 goto end_op;
1936 case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
1937 case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
1938 rcache_clean();
1939 tmp = rcache_get_reg_arg(0, GET_Rm());
1940 tmp3 = (op & 0x100) >> 8;
1941 emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
1942 tmp = emit_memhandler_read(tmp3);
1943 tmp2 = rcache_get_reg(0, RC_GR_WRITE);
1944 emith_sext(tmp2, tmp, 8 << tmp3);
1945 rcache_free_tmp(tmp);
1946 goto end_op;
1947 case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
1948 // XXX: could use cmn
1949 tmp = rcache_get_tmp();
1950 tmp2 = rcache_get_reg(0, RC_GR_READ);
8796b7ee 1951 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1952 if (drcf.delayed_op)
1953 DELAY_SAVE_T(sr);
52d759c3 1954 emith_move_r_imm_s8(tmp, op & 0xff);
8796b7ee 1955 emith_bic_r_imm(sr, T);
52d759c3 1956 emith_cmp_r_r(tmp2, tmp);
8796b7ee 1957 emit_or_t_if_eq(sr);
52d759c3 1958 rcache_free_tmp(tmp);
1959 goto end_op;
1960 case 0x0d00: // BT/S label 10001101dddddddd
1961 case 0x0f00: // BF/S label 10001111dddddddd
679af8a3 1962 DELAYED_OP;
1963 cycles--;
679af8a3 1964 // fallthrough
44e6452e 1965 case 0x0900: // BT label 10001001dddddddd
1966 case 0x0b00: // BF label 10001011dddddddd
1967 // will handle conditional branches later
1968 pending_branch_cond = (op & 0x0200) ? DCOND_EQ : DCOND_NE;
1969 i = ((signed int)(op << 24) >> 23);
1970 pending_branch_pc = pc + i + 2;
e898de13 1971 cycles += 2;
e898de13 1972 goto end_op;
44e6452e 1973 }
679af8a3 1974 goto default_;
679af8a3 1975
52d759c3 1976 /////////////////////////////////////////////
1977 case 0x09:
1978 // MOV.W @(disp,PC),Rn 1001nnnndddddddd
f0d7b1fa 1979 rcache_clean();
1980 tmp = rcache_get_tmp_arg(0);
1981 emith_move_r_imm(tmp, pc + (op & 0xff) * 2 + 2);
1982 tmp = emit_memhandler_read(1);
1983 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1984 emith_sext(tmp2, tmp, 16);
1985 rcache_free_tmp(tmp);
1986 goto end_op;
52d759c3 1987
3863edbd 1988 /////////////////////////////////////////////
679af8a3 1989 case 0x0a:
1990 // BRA label 1010dddddddddddd
1991 DELAYED_OP;
44e6452e 1992 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
679af8a3 1993 tmp = ((signed int)(op << 20) >> 19);
44e6452e 1994 out_pc = pc + tmp + 2;
1995 if (tmp == (u32)-4)
1996 emith_clear_msb(sr, sr, 20); // burn cycles
679af8a3 1997 cycles++;
e898de13 1998 break;
679af8a3 1999
3863edbd 2000 /////////////////////////////////////////////
679af8a3 2001 case 0x0b:
2002 // BSR label 1011dddddddddddd
2003 DELAYED_OP;
e898de13 2004 emit_move_r_imm32(SHR_PR, pc + 2);
44e6452e 2005 tmp = ((signed int)(op << 20) >> 19);
2006 out_pc = pc + tmp + 2;
2007 cycles++;
2008 break;
679af8a3 2009
52d759c3 2010 /////////////////////////////////////////////
2011 case 0x0c:
2012 switch (op & 0x0f00)
2013 {
2014 case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
2015 case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
2016 case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
2017 rcache_clean();
2018 tmp = rcache_get_reg_arg(0, SHR_GBR);
2019 tmp2 = rcache_get_reg_arg(1, SHR_R0);
2020 tmp3 = (op & 0x300) >> 8;
2021 emith_add_r_imm(tmp, (op & 0xff) << tmp3);
e05b81fc 2022 emit_memhandler_write(tmp3, pc, drcf.delayed_op);
52d759c3 2023 goto end_op;
2024 case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
2025 case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
2026 case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
2027 rcache_clean();
2028 tmp = rcache_get_reg_arg(0, SHR_GBR);
2029 tmp3 = (op & 0x300) >> 8;
2030 emith_add_r_imm(tmp, (op & 0xff) << tmp3);
2031 tmp = emit_memhandler_read(tmp3);
2032 tmp2 = rcache_get_reg(0, RC_GR_WRITE);
2033 if (tmp3 != 2) {
2034 emith_sext(tmp2, tmp, 8 << tmp3);
2035 } else
2036 emith_move_r_r(tmp2, tmp);
2037 rcache_free_tmp(tmp);
2038 goto end_op;
2039 case 0x0300: // TRAPA #imm 11000011iiiiiiii
2040 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2041 emith_sub_r_imm(tmp, 4*2);
2042 rcache_clean();
2043 // push SR
2044 tmp = rcache_get_reg_arg(0, SHR_SP);
2045 emith_add_r_imm(tmp, 4);
2046 tmp = rcache_get_reg_arg(1, SHR_SR);
18b94127 2047 emith_clear_msb(tmp, tmp, 22);
e05b81fc 2048 emit_memhandler_write(2, pc, drcf.delayed_op);
52d759c3 2049 // push PC
2050 rcache_get_reg_arg(0, SHR_SP);
2051 tmp = rcache_get_tmp_arg(1);
2052 emith_move_r_imm(tmp, pc);
e05b81fc 2053 emit_memhandler_write(2, pc, drcf.delayed_op);
52d759c3 2054 // obtain new PC
2055 tmp = rcache_get_reg_arg(0, SHR_VBR);
2056 emith_add_r_imm(tmp, (op & 0xff) * 4);
2057 tmp = emit_memhandler_read(2);
2058 tmp2 = rcache_get_reg(SHR_PC, RC_GR_WRITE);
2059 emith_move_r_r(tmp2, tmp);
2060 rcache_free_tmp(tmp);
44e6452e 2061 out_pc = (u32)-1;
52d759c3 2062 cycles += 7;
44e6452e 2063 goto end_op;
52d759c3 2064 case 0x0700: // MOVA @(disp,PC),R0 11000111dddddddd
2065 emit_move_r_imm32(SHR_R0, (pc + (op & 0xff) * 4 + 2) & ~3);
2066 goto end_op;
2067 case 0x0800: // TST #imm,R0 11001000iiiiiiii
8796b7ee 2068 tmp = rcache_get_reg(SHR_R0, RC_GR_READ);
2069 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2070 if (drcf.delayed_op)
2071 DELAY_SAVE_T(sr);
8796b7ee 2072 emith_bic_r_imm(sr, T);
52d759c3 2073 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 2074 emit_or_t_if_eq(sr);
52d759c3 2075 goto end_op;
2076 case 0x0900: // AND #imm,R0 11001001iiiiiiii
2077 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2078 emith_and_r_imm(tmp, op & 0xff);
2079 goto end_op;
2080 case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
2081 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2082 emith_eor_r_imm(tmp, op & 0xff);
2083 goto end_op;
2084 case 0x0b00: // OR #imm,R0 11001011iiiiiiii
2085 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2086 emith_or_r_imm(tmp, op & 0xff);
2087 goto end_op;
2088 case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
8796b7ee 2089 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2090 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2091 if (drcf.delayed_op)
2092 DELAY_SAVE_T(sr);
8796b7ee 2093 emith_bic_r_imm(sr, T);
52d759c3 2094 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 2095 emit_or_t_if_eq(sr);
52d759c3 2096 rcache_free_tmp(tmp);
2097 cycles += 2;
2098 goto end_op;
2099 case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
2100 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2101 emith_and_r_imm(tmp, op & 0xff);
8796b7ee 2102 goto end_rmw_op;
52d759c3 2103 case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
2104 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2105 emith_eor_r_imm(tmp, op & 0xff);
8796b7ee 2106 goto end_rmw_op;
52d759c3 2107 case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
2108 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2109 emith_or_r_imm(tmp, op & 0xff);
8796b7ee 2110 end_rmw_op:
2111 tmp2 = rcache_get_tmp_arg(1);
2112 emith_move_r_r(tmp2, tmp);
2113 rcache_free_tmp(tmp);
2114 tmp3 = rcache_get_reg_arg(0, SHR_GBR);
2115 tmp4 = rcache_get_reg(SHR_R0, RC_GR_READ);
2116 emith_add_r_r(tmp3, tmp4);
e05b81fc 2117 emit_memhandler_write(0, pc, drcf.delayed_op);
52d759c3 2118 cycles += 2;
2119 goto end_op;
2120 }
2121 goto default_;
2122
2123 /////////////////////////////////////////////
2124 case 0x0d:
2125 // MOV.L @(disp,PC),Rn 1101nnnndddddddd
f0d7b1fa 2126 rcache_clean();
2127 tmp = rcache_get_tmp_arg(0);
2128 emith_move_r_imm(tmp, (pc + (op & 0xff) * 4 + 2) & ~3);
2129 tmp = emit_memhandler_read(2);
2130 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
2131 emith_move_r_r(tmp2, tmp);
2132 rcache_free_tmp(tmp);
2133 goto end_op;
52d759c3 2134
2135 /////////////////////////////////////////////
2136 case 0x0e:
2137 // MOV #imm,Rn 1110nnnniiiiiiii
2138 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
2139 emith_move_r_imm_s8(tmp, op & 0xff);
2140 goto end_op;
2141
679af8a3 2142 default:
2143 default_:
f0d7b1fa 2144 elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
2145 sh2->is_slave ? 's' : 'm', op, pc - 2);
2146#ifdef DRC_DEBUG_INTERP
679af8a3 2147 emit_move_r_imm32(SHR_PC, pc - 2);
c18edb34 2148 rcache_flush();
f4bb5d6b 2149 emith_pass_arg_r(0, CONTEXT_REG);
2150 emith_pass_arg_imm(1, op);
679af8a3 2151 emith_call(sh2_do_op);
f0d7b1fa 2152#endif
679af8a3 2153 break;
2154 }
2155
e898de13 2156end_op:
44e6452e 2157 // conditional branch handling (with/without delay)
2158 if (pending_branch_cond != -1 && drcf.delayed_op != 2)
2159 {
2160 u32 target_pc = pending_branch_pc;
2161 void *target;
2162
18b94127 2163 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2164 // handle cycles
e05b81fc 2165 FLUSH_CYCLES(sr);
18b94127 2166 rcache_clean();
18b94127 2167 if (drcf.use_saved_t)
2168 emith_tst_r_imm(sr, T_save);
2169 else
2170 emith_tst_r_imm(sr, T);
18b94127 2171
44e6452e 2172 if (find_in_array(branch_target_pc, branch_target_count, target_pc) >= 0) {
2173 // local branch
2174 // XXX: jumps back can be linked already
2175 branch_patch_pc[branch_patch_count] = target_pc;
2176 branch_patch_ptr[branch_patch_count] = tcache_ptr;
2177 emith_jump_cond_patchable(pending_branch_cond, tcache_ptr);
2178
2179 branch_patch_count++;
2180 if (branch_patch_count == MAX_LOCAL_BRANCHES) {
2181 printf("warning: too many local branches\n");
2182 break;
2183 }
2184 }
2185 else {
2186 // can't resolve branch locally, make a block exit
2187 emit_move_r_imm32(SHR_PC, target_pc);
2188 rcache_clean();
2189
2190 target = dr_prepare_ext_branch(target_pc, sh2, tcache_id);
2191 if (target == NULL)
2192 return NULL;
2193 emith_jump_cond_patchable(pending_branch_cond, target);
18b94127 2194 }
44e6452e 2195
2196 drcf.use_saved_t = 0;
2197 pending_branch_cond = -1;
e898de13 2198 }
44e6452e 2199
18b94127 2200 // test irq?
e05b81fc 2201 // XXX: delay slots..
2202 if (drcf.test_irq && drcf.delayed_op != 2) {
2203 if (!drcf.delayed_op)
2204 emit_move_r_imm32(SHR_PC, pc);
2205 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2206 FLUSH_CYCLES(sr);
2207 rcache_flush();
2208 emith_call(sh2_drc_test_irq);
2209 drcf.test_irq = 0;
2210 }
e898de13 2211
f4bb5d6b 2212 do_host_disasm(tcache_id);
52d759c3 2213
44e6452e 2214 if (out_pc != 0 && drcf.delayed_op != 2)
2215 break;
2216 }
f4bb5d6b 2217
18b94127 2218 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 2219 FLUSH_CYCLES(tmp);
18b94127 2220 rcache_flush();
44e6452e 2221
2222 if (out_pc == (u32)-1) {
2223 // indirect jump -> back to dispatcher
2224 emith_jump(sh2_drc_dispatcher);
2225 } else {
2226 void *target;
2227 if (out_pc == 0)
2228 out_pc = pc;
2229 emit_move_r_imm32(SHR_PC, out_pc);
2230 rcache_flush();
2231
2232 target = dr_prepare_ext_branch(out_pc, sh2, tcache_id);
2233 if (target == NULL)
2234 return NULL;
2235 emith_jump_patchable(target);
2236 }
18b94127 2237
2238 // link local branches
2239 for (i = 0; i < branch_patch_count; i++) {
2240 void *target;
2241 int t;
18b94127 2242 t = find_in_array(branch_target_pc, branch_target_count, branch_patch_pc[i]);
44e6452e 2243 target = branch_target_ptr[t];
2244 if (target == NULL) {
2245 // flush pc and go back to dispatcher (should no longer happen)
18b94127 2246 printf("stray branch to %08x %p\n", branch_patch_pc[i], tcache_ptr);
2247 target = tcache_ptr;
2248 emit_move_r_imm32(SHR_PC, branch_patch_pc[i]);
2249 rcache_flush();
e05b81fc 2250 emith_jump(sh2_drc_dispatcher);
18b94127 2251 }
2252 emith_jump_patch(branch_patch_ptr[i], target);
2253 }
2254
44e6452e 2255 this_block->end_addr = pc;
2256
f4bb5d6b 2257 // mark memory blocks as containing compiled code
18b94127 2258 if (tcache_id != 0) {
f4bb5d6b 2259 // data array, BIOS
2260 u16 *drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
18b94127 2261 tmp = (this_block->addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
f4bb5d6b 2262 tmp2 = (this_block->end_addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
18b94127 2263 drcblk[tmp] = (blkid_main << 1) | 1;
f4bb5d6b 2264 for (++tmp; tmp < tmp2; tmp++) {
2265 if (drcblk[tmp])
18b94127 2266 continue; // dont overwrite overlay block(s)
2267 drcblk[tmp] = blkid_main << 1;
f4bb5d6b 2268 }
2269 }
2270 else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
18b94127 2271 tmp = (this_block->addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
f4bb5d6b 2272 tmp2 = (this_block->end_addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
18b94127 2273 Pico32xMem->drcblk_ram[tmp] = (blkid_main << 1) | 1;
f4bb5d6b 2274 for (++tmp; tmp < tmp2; tmp++) {
2275 if (Pico32xMem->drcblk_ram[tmp])
18b94127 2276 continue;
2277 Pico32xMem->drcblk_ram[tmp] = blkid_main << 1;
f4bb5d6b 2278 }
679af8a3 2279 }
2280
f4bb5d6b 2281 tcache_ptrs[tcache_id] = tcache_ptr;
2282
553c3eaa 2283#ifdef ARM
2284 cache_flush_d_inval_i(block_entry, tcache_ptr);
2285#endif
2286
f4bb5d6b 2287 do_host_disasm(tcache_id);
2288 dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
2289 tcache_id, block_counts[tcache_id],
2290 tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
2291 insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
2292 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
2293 dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
18b94127 2294/*
2295 printf("~~~\n");
2296 tcache_dsm_ptrs[tcache_id] = block_entry;
2297 do_host_disasm(tcache_id);
2298 printf("~~~\n");
2299*/
2300
553c3eaa 2301#if (DRC_DEBUG & 2)
2302 fflush(stdout);
2303#endif
2304
679af8a3 2305 return block_entry;
679af8a3 2306}
2307
e05b81fc 2308static void sh2_generate_utils(void)
679af8a3 2309{
e05b81fc 2310 int arg0, arg1, arg2, sr, tmp;
2311 void *sh2_drc_write_end, *sh2_drc_write_slot_end;
52d759c3 2312
e05b81fc 2313 host_arg2reg(arg0, 0);
2314 host_arg2reg(arg1, 1);
2315 host_arg2reg(arg2, 2);
2316 emith_move_r_r(arg0, arg0); // nop
679af8a3 2317
e05b81fc 2318 // sh2_drc_exit(void)
2319 sh2_drc_exit = (void *)tcache_ptr;
2320 emit_do_static_regs(1, arg2);
2321 emith_sh2_drc_exit();
679af8a3 2322
e05b81fc 2323 // sh2_drc_dispatcher(void)
2324 sh2_drc_dispatcher = (void *)tcache_ptr;
2325 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2326 emith_cmp_r_imm(sr, 0);
2327 emith_jump_cond(DCOND_LT, sh2_drc_exit);
2328 rcache_invalidate();
2329 emith_ctx_read(arg0, SHR_PC * 4);
2330 emith_ctx_read(arg1, offsetof(SH2, is_slave));
2331 emith_add_r_r_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
2332 emith_call(lookup_block);
2333 emit_block_entry();
2334 // lookup failed, call sh2_translate()
2335 emith_move_r_r(arg0, CONTEXT_REG);
2336 emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
2337 emith_call(sh2_translate);
2338 emit_block_entry();
2339 // sh2_translate() failed, flush cache and retry
2340 emith_ctx_read(arg0, offsetof(SH2, drc_tmp));
2341 emith_call(flush_tcache);
2342 emith_move_r_r(arg0, CONTEXT_REG);
2343 emith_ctx_read(arg1, offsetof(SH2, drc_tmp));
2344 emith_call(sh2_translate);
2345 emit_block_entry();
2346 // XXX: can't translate, fail
2347 emith_call(exit);
2348
2349 // sh2_drc_test_irq(void)
2350 // assumes it's called from main function (may jump to dispatcher)
2351 sh2_drc_test_irq = (void *)tcache_ptr;
2352 emith_ctx_read(arg1, offsetof(SH2, pending_level));
2353 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2354 emith_lsr(arg0, sr, I_SHIFT);
2355 emith_and_r_imm(arg0, 0x0f);
2356 emith_cmp_r_r(arg1, arg0); // pending_level > ((sr >> 4) & 0x0f)?
2357 EMITH_SJMP_START(DCOND_GT);
2358 emith_ret_c(DCOND_LE); // nope, return
2359 EMITH_SJMP_END(DCOND_GT);
2360 // adjust SP
2361 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2362 emith_sub_r_imm(tmp, 4*2);
2363 rcache_clean();
2364 // push SR
2365 tmp = rcache_get_reg_arg(0, SHR_SP);
2366 emith_add_r_imm(tmp, 4);
2367 tmp = rcache_get_reg_arg(1, SHR_SR);
2368 emith_clear_msb(tmp, tmp, 22);
2369 emith_move_r_r(arg2, CONTEXT_REG);
2370 emith_call(p32x_sh2_write32);
2371 rcache_invalidate();
2372 // push PC
2373 rcache_get_reg_arg(0, SHR_SP);
2374 emith_ctx_read(arg1, SHR_PC * 4);
2375 emith_move_r_r(arg2, CONTEXT_REG);
2376 emith_call(p32x_sh2_write32);
2377 rcache_invalidate();
2378 // update I, cycles, do callback
2379 emith_ctx_read(arg1, offsetof(SH2, pending_level));
2380 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2381 emith_bic_r_imm(sr, I);
2382 emith_or_r_r_lsl(sr, arg1, I_SHIFT);
2383 emith_sub_r_imm(sr, 13 << 12); // at least 13 cycles
2384 rcache_flush();
2385 emith_move_r_r(arg0, CONTEXT_REG);
2386 emith_call_ctx(offsetof(SH2, irq_callback)); // vector = sh2->irq_callback(sh2, level);
2387 // obtain new PC
2388 emith_lsl(arg0, arg0, 2);
2389 emith_ctx_read(arg1, SHR_VBR * 4);
2390 emith_add_r_r(arg0, arg1);
2391 emit_memhandler_read(2);
2392 emith_ctx_write(arg0, SHR_PC * 4);
2393#ifdef __i386__
2394 emith_add_r_imm(xSP, 4); // fix stack
2395#endif
2396 emith_jump(sh2_drc_dispatcher);
2397 rcache_invalidate();
2398
2399 // sh2_drc_entry(SH2 *sh2)
2400 sh2_drc_entry = (void *)tcache_ptr;
2401 emith_sh2_drc_entry();
2402 emith_move_r_r(CONTEXT_REG, arg0); // move ctx, arg0
2403 emit_do_static_regs(0, arg2);
2404 emith_call(sh2_drc_test_irq);
2405 emith_jump(sh2_drc_dispatcher);
2406
2407 // write-caused irq detection
2408 sh2_drc_write_end = tcache_ptr;
2409 emith_tst_r_r(arg0, arg0);
2410 EMITH_SJMP_START(DCOND_NE);
2411 emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp)); // return
2412 EMITH_SJMP_END(DCOND_NE);
2413 // since PC is up to date, jump to it's block instead of returning
2414 emith_call(sh2_drc_test_irq);
2415 emith_jump_ctx(offsetof(SH2, drc_tmp));
2416
2417 // write-caused irq detection for writes in delay slot
2418 sh2_drc_write_slot_end = tcache_ptr;
2419 emith_tst_r_r(arg0, arg0);
2420 EMITH_SJMP_START(DCOND_NE);
2421 emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp));
2422 EMITH_SJMP_END(DCOND_NE);
2423 // just burn cycles to get back to dispatcher after branch is handled
2424 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2425 emith_ctx_write(sr, offsetof(SH2, irq_cycles));
2426 emith_clear_msb(sr, sr, 20); // clear cycles
2427 rcache_flush();
2428 emith_jump_ctx(offsetof(SH2, drc_tmp));
2429
2430 // sh2_drc_write8(u32 a, u32 d)
2431 sh2_drc_write8 = (void *)tcache_ptr;
2432 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2433 emith_ctx_read(arg2, offsetof(SH2, write8_tab));
2434 emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
2435
2436 // sh2_drc_write16(u32 a, u32 d)
2437 sh2_drc_write16 = (void *)tcache_ptr;
2438 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2439 emith_ctx_read(arg2, offsetof(SH2, write16_tab));
2440 emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
2441
2442 // sh2_drc_write8_slot(u32 a, u32 d)
2443 sh2_drc_write8_slot = (void *)tcache_ptr;
2444 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2445 emith_ctx_read(arg2, offsetof(SH2, write8_tab));
2446 emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
2447
2448 // sh2_drc_write16_slot(u32 a, u32 d)
2449 sh2_drc_write16_slot = (void *)tcache_ptr;
2450 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2451 emith_ctx_read(arg2, offsetof(SH2, write16_tab));
2452 emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
2453
2454 rcache_invalidate();
2455#if (DRC_DEBUG & 2)
2456 host_dasm_new_symbol(sh2_drc_entry);
2457 host_dasm_new_symbol(sh2_drc_dispatcher);
2458 host_dasm_new_symbol(sh2_drc_exit);
2459 host_dasm_new_symbol(sh2_drc_test_irq);
2460 host_dasm_new_symbol(sh2_drc_write_end);
2461 host_dasm_new_symbol(sh2_drc_write_slot_end);
2462 host_dasm_new_symbol(sh2_drc_write8);
2463 host_dasm_new_symbol(sh2_drc_write8_slot);
2464 host_dasm_new_symbol(sh2_drc_write16);
2465 host_dasm_new_symbol(sh2_drc_write16_slot);
679af8a3 2466#endif
679af8a3 2467}
2468
f4bb5d6b 2469static void sh2_smc_rm_block(u16 *drcblk, u16 *p, block_desc *btab, u32 a)
2470{
2471 u16 id = *p >> 1;
2472 block_desc *bd = btab + id;
2473
18b94127 2474 // FIXME: skip subblocks; do both directions
44e6452e 2475 // FIXME: collect all branches
f4bb5d6b 2476 dbg(1, " killing block %08x", bd->addr);
2477 bd->addr = bd->end_addr = 0;
2478
2479 while (p > drcblk && (p[-1] >> 1) == id)
2480 p--;
2481
2482 // check for possible overlay block
2483 if (p > 0 && p[-1] != 0) {
2484 bd = btab + (p[-1] >> 1);
2485 if (bd->addr <= a && a < bd->end_addr)
2486 sh2_smc_rm_block(drcblk, p - 1, btab, a);
2487 }
2488
2489 do {
2490 *p++ = 0;
2491 }
2492 while ((*p >> 1) == id);
2493}
2494
2495void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
2496{
2497 u16 *drcblk = Pico32xMem->drcblk_ram;
2498 u16 *p = drcblk + ((a & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT);
2499
2500 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
2501 sh2_smc_rm_block(drcblk, p, block_tables[0], a);
2502}
2503
2504void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
2505{
2506 u16 *drcblk = Pico32xMem->drcblk_da[cpuid];
2507 u16 *p = drcblk + ((a & 0xfff) >> SH2_DRCBLK_DA_SHIFT);
2508
2509 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
2510 sh2_smc_rm_block(drcblk, p, block_tables[1 + cpuid], a);
2511}
2512
52d759c3 2513void sh2_execute(SH2 *sh2c, int cycles)
679af8a3 2514{
e05b81fc 2515 int ret_cycles;
52d759c3 2516 sh2 = sh2c; // XXX
2517
2518 sh2c->cycles_aim += cycles;
2519 cycles = sh2c->cycles_aim - sh2c->cycles_done;
679af8a3 2520
2521 // cycles are kept in SHR_SR unused bits (upper 20)
18b94127 2522 // bit19 contains T saved for delay slot
2523 // others are usual SH2 flags
52d759c3 2524 sh2c->sr &= 0x3f3;
2525 sh2c->sr |= cycles << 12;
e05b81fc 2526 sh2_drc_entry(sh2c);
679af8a3 2527
e05b81fc 2528 // TODO: irq cycles
2529 ret_cycles = (signed int)sh2c->sr >> 12;
2530 if (ret_cycles > 0)
2531 printf("warning: drc returned with cycles: %d\n", ret_cycles);
679af8a3 2532
e05b81fc 2533 sh2c->cycles_done += cycles - ret_cycles;
679af8a3 2534}
2535
f4bb5d6b 2536#if (DRC_DEBUG & 1)
9bb5d91c 2537void block_stats(void)
f4bb5d6b 2538{
2539 int c, b, i, total = 0;
2540
9bb5d91c 2541 printf("block stats:\n");
f4bb5d6b 2542 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
2543 for (i = 0; i < block_counts[b]; i++)
2544 if (block_tables[b][i].addr != 0)
2545 total += block_tables[b][i].refcount;
2546
2547 for (c = 0; c < 10; c++) {
2548 block_desc *blk, *maxb = NULL;
2549 int max = 0;
2550 for (b = 0; b < ARRAY_SIZE(block_tables); b++) {
2551 for (i = 0; i < block_counts[b]; i++) {
2552 blk = &block_tables[b][i];
2553 if (blk->addr != 0 && blk->refcount > max) {
2554 max = blk->refcount;
2555 maxb = blk;
2556 }
2557 }
2558 }
2559 if (maxb == NULL)
2560 break;
2561 printf("%08x %9d %2.3f%%\n", maxb->addr, maxb->refcount,
2562 (double)maxb->refcount / total * 100.0);
2563 maxb->refcount = 0;
2564 }
553c3eaa 2565
2566 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
2567 for (i = 0; i < block_counts[b]; i++)
2568 block_tables[b][i].refcount = 0;
f4bb5d6b 2569}
553c3eaa 2570#else
2571#define block_stats()
f4bb5d6b 2572#endif
2573
553c3eaa 2574void sh2_drc_flush_all(void)
2575{
2576 block_stats();
2577 flush_tcache(0);
2578 flush_tcache(1);
2579 flush_tcache(2);
2580}
2581
679af8a3 2582int sh2_drc_init(SH2 *sh2)
2583{
44e6452e 2584 int i;
7f5a3fc1 2585
44e6452e 2586 if (block_tables[0] == NULL)
2587 {
2588 for (i = 0; i < TCACHE_BUFFERS; i++) {
2589 block_tables[i] = calloc(block_max_counts[i], sizeof(*block_tables[0]));
2590 if (block_tables[i] == NULL)
2591 goto fail;
2592 // max 2 block links (exits) per block
2593 block_links[i] = calloc(block_max_counts[i] * 2, sizeof(*block_links[0]));
2594 if (block_links[i] == NULL)
2595 goto fail;
2596 }
2597 memset(block_counts, 0, sizeof(block_counts));
2598 memset(block_link_counts, 0, sizeof(block_link_counts));
e898de13 2599
44e6452e 2600 drc_cmn_init();
8796b7ee 2601 tcache_ptr = tcache;
2602 sh2_generate_utils();
8b4f38f4 2603#ifdef ARM
2604 cache_flush_d_inval_i(tcache, tcache_ptr);
2605#endif
8796b7ee 2606
8796b7ee 2607 tcache_bases[0] = tcache_ptrs[0] = tcache_ptr;
44e6452e 2608 for (i = 1; i < ARRAY_SIZE(tcache_bases); i++)
f4bb5d6b 2609 tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
f4bb5d6b 2610
553c3eaa 2611 // tmp
2612 PicoOpt |= POPT_DIS_VDP_FIFO;
2613
f4bb5d6b 2614#if (DRC_DEBUG & 2)
2615 for (i = 0; i < ARRAY_SIZE(block_tables); i++)
2616 tcache_dsm_ptrs[i] = tcache_bases[i];
8796b7ee 2617 // disasm the utils
2618 tcache_dsm_ptrs[0] = tcache;
2619 do_host_disasm(0);
f4bb5d6b 2620#endif
e898de13 2621#if (DRC_DEBUG & 1)
2622 hash_collisions = 0;
2623#endif
679af8a3 2624 }
2625
f4bb5d6b 2626 if (hash_table == NULL) {
2627 hash_table = calloc(sizeof(hash_table[0]), MAX_HASH_ENTRIES);
2628 if (hash_table == NULL)
44e6452e 2629 goto fail;
f4bb5d6b 2630 }
41397701 2631
679af8a3 2632 return 0;
44e6452e 2633
2634fail:
2635 sh2_drc_finish(sh2);
2636 return -1;
41397701 2637}
2638
e898de13 2639void sh2_drc_finish(SH2 *sh2)
2640{
44e6452e 2641 int i;
2642
f4bb5d6b 2643 if (block_tables[0] != NULL) {
f4bb5d6b 2644 block_stats();
44e6452e 2645
2646 for (i = 0; i < TCACHE_BUFFERS; i++) {
2647#if (DRC_DEBUG & 2)
2648 printf("~~~ tcache %d\n", i);
2649 tcache_dsm_ptrs[i] = tcache_bases[i];
2650 tcache_ptr = tcache_ptrs[i];
2651 do_host_disasm(i);
2652#endif
2653
2654 if (block_tables[i] != NULL)
2655 free(block_tables[i]);
2656 block_tables[i] = NULL;
2657 if (block_links[i] == NULL)
2658 free(block_links[i]);
2659 block_links[i] = NULL;
2660 }
7f5a3fc1 2661
2662 drc_cmn_cleanup();
e898de13 2663 }
2664
f4bb5d6b 2665 if (hash_table != NULL) {
2666 free(hash_table);
2667 hash_table = NULL;
2668 }
e898de13 2669}